diff options
1056 files changed, 29915 insertions, 16525 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-fcoe b/Documentation/ABI/testing/sysfs-bus-fcoe index 469d09c02f6b..50e2a80ea28f 100644 --- a/Documentation/ABI/testing/sysfs-bus-fcoe +++ b/Documentation/ABI/testing/sysfs-bus-fcoe @@ -9,19 +9,19 @@ Attributes: 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/link_fail: Link Error Status Block (LESB) link failure count. - lesb_vlink_fail: Link Error Status Block (LESB) virtual link + lesb/vlink_fail: Link Error Status Block (LESB) virtual link failure count. - lesb_miss_fka: Link Error Status Block (LESB) missed FCoE + 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/symb_err: Link Error Status Block (LESB) symbolic error count. - lesb_err_block: Link Error Status Block (LESB) block error count. + lesb/err_block: Link Error Status Block (LESB) block error count. - lesb_fcs_error: Link Error Status Block (LESB) Fibre Channel + lesb/fcs_error: Link Error Status Block (LESB) Fibre Channel Serivces error count. Notes: ctlr_X (global increment starting at 0) diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index c6ae4c9d0e0c..4fdf6b562d1c 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2582,6 +2582,10 @@ ioctls.</para> <listitem> <para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para> </listitem> + <listitem> + <para>Vendor and device specific media bus pixel formats. + <xref linkend="v4l2-mbus-vendor-spec-fmts" />.</para> + </listitem> </itemizedlist> </section> diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 272a5f718509..7fe5be1d3bbb 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -1586,7 +1586,6 @@ frame counter of the frame that is currently displayed (decoded). This value is the decoder is started.</entry> </row> - <row><entry></entry></row> <row> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE</constant> </entry> @@ -2270,6 +2269,14 @@ Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry> </row> <row><entry></entry></row> + <row id="v4l2-mpeg-video-vbv-delay"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_DELAY</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">Sets the initial delay in milliseconds for +VBV buffer control.</entry> + </row> + + <row><entry></entry></row> <row> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant> </entry> <entry>integer</entry> @@ -2334,6 +2341,265 @@ Applicable to the MPEG4 decoder.</entry> </row><row><entry spanname="descr">vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.</entry> </row> + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enable generation of frame packing supplemental enhancement information in the encoded bitstream. +The frame packing SEI message contains the arrangement of L and R planes for 3D viewing. Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Sets current frame as frame0 in frame packing SEI. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-sei-fp-arrangement-type"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_sei_fp_arrangement_type</entry> + </row> + <row><entry spanname="descr">Frame packing arrangement type for H264 SEI. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHEKERBOARD</constant> </entry> + <entry>Pixels are alternatively from L and R.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN</constant> </entry> + <entry>L and R are interlaced by column.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW</constant> </entry> + <entry>L and R are interlaced by row.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE</constant> </entry> + <entry>L is on the left, R on the right.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM</constant> </entry> + <entry>L is on top, R on bottom.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL</constant> </entry> + <entry>One view per frame.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enables flexible macroblock ordering in the encoded bitstream. It is a technique +used for restructuring the ordering of macroblocks in pictures. Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-fmo-map-type"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_fmo_map_type</entry> + </row> + <row><entry spanname="descr">When using FMO, the map type divides the image in different scan patterns of macroblocks. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES</constant> </entry> + <entry>Slices are interleaved one after other with macroblocks in run length order.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES</constant> </entry> + <entry>Scatters the macroblocks based on a mathematical function known to both encoder and decoder.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER</constant> </entry> + <entry>Macroblocks arranged in rectangular areas or regions of interest.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT</constant> </entry> + <entry>Slice groups grow in a cyclic way from centre to outwards.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN</constant> </entry> + <entry>Slice groups grow in raster scan pattern from left to right.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN</constant> </entry> + <entry>Slice groups grow in wipe scan pattern from top to bottom.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT</constant> </entry> + <entry>User defined map type.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Number of slice groups in FMO. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-fmo-change-direction"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_fmo_change_dir</entry> + </row> + <row><entry spanname="descr">Specifies a direction of the slice group change for raster and wipe maps. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT</constant> </entry> + <entry>Raster scan or wipe right.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT</constant> </entry> + <entry>Reverse raster scan or wipe left.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Specifies the size of the first slice group for raster and wipe map. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Specifies the number of consecutive macroblocks for the interleaved map. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ASO</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enables arbitrary slice ordering in encoded bitstream. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">Specifies the slice order in ASO. Applicable to the H264 encoder. +The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit):</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry>Bit 0:15</entry> + <entry>Slice ID</entry> + </row> + <row> + <entry>Bit 16:32</entry> + <entry>Slice position or order</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enables H264 hierarchical coding. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-hierarchical-coding-type"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_hierarchical_coding_type</entry> + </row> + <row><entry spanname="descr">Specifies the hierarchical coding type. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B</constant> </entry> + <entry>Hierarchical B coding.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P</constant> </entry> + <entry>Hierarchical P coding.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Specifies the number of hierarchical coding layers. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">Specifies a user defined QP for each layer. Applicable to the H264 encoder. +The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit):</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry>Bit 0:15</entry> + <entry>QP value</entry> + </row> + <row> + <entry>Bit 16:32</entry> + <entry>Layer number</entry> + </row> + </tbody> + </entrytbl> + </row> + </tbody> </tgroup> </table> @@ -4267,6 +4533,16 @@ interface and may change in the future.</para> pixels / second. </entry> </row> + <row> + <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN</constant></entry> + <entry>menu</entry> + </row> + <row id="v4l2-test-pattern"> + <entry spanname="descr"> Some capture/display/sensor devices have + the capability to generate test pattern images. These hardware + specific test patterns can be used to test if a device is working + properly.</entry> + </row> <row><entry></entry></row> </tbody> </tgroup> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 97f785add841..b5d1cbdc558b 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -677,8 +677,10 @@ memory, set by the application. See <xref linkend="userp" /> for details. <entry><structfield>length</structfield></entry> <entry></entry> <entry>Size of the buffer (not the payload) in bytes for the - single-planar API. For the multi-planar API should contain the - number of elements in the <structfield>planes</structfield> array. + single-planar API. For the multi-planar API the application sets + this to the number of elements in the <structfield>planes</structfield> + array. The driver will fill in the actual number of valid elements in + that array. </entry> </row> <row> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml index 5274c24d11e0..a990b34d911a 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml @@ -1,11 +1,13 @@ - <refentry id="V4L2-PIX-FMT-NV12M"> + <refentry> <refmeta> - <refentrytitle>V4L2_PIX_FMT_NV12M ('NM12')</refentrytitle> + <refentrytitle>V4L2_PIX_FMT_NV12M ('NM12'), V4L2_PIX_FMT_NV21M ('NM21'), V4L2_PIX_FMT_NV12MT_16X16</refentrytitle> &manvol; </refmeta> <refnamediv> - <refname> <constant>V4L2_PIX_FMT_NV12M</constant></refname> - <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> with planes + <refname id="V4L2-PIX-FMT-NV12M"><constant>V4L2_PIX_FMT_NV12M</constant></refname> + <refname id="V4L2-PIX-FMT-NV21M"><constant>V4L2_PIX_FMT_NV21M</constant></refname> + <refname id="V4L2-PIX-FMT-NV12MT_16X16"><constant>V4L2_PIX_FMT_NV12MT_16X16</constant></refname> + <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> and <constant>V4L2_PIX_FMT_NV21</constant> with planes non contiguous in memory. </refpurpose> </refnamediv> <refsect1> @@ -22,7 +24,12 @@ The CbCr plane is the same width, in bytes, as the Y plane (and of the image), but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example, Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to Y'<subscript>00</subscript>, Y'<subscript>01</subscript>, -Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. </para> +Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. +<constant>V4L2_PIX_FMT_NV12MT_16X16</constant> is the tiled version of +<constant>V4L2_PIX_FMT_NV12M</constant> with 16x16 macroblock tiles. Here pixels +are arranged in 16x16 2D tiles and tiles are arranged in linear order in memory. +<constant>V4L2_PIX_FMT_NV21M</constant> is the same as <constant>V4L2_PIX_FMT_NV12M</constant> +except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para> <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be used only in drivers and applications that support the multi-planar API, diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 1ddbfabe3195..bf94f417592c 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -758,6 +758,11 @@ extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see <entry>'AVC1'</entry> <entry>H264 video elementary stream without start codes.</entry> </row> + <row id="V4L2-PIX-FMT-H264-MVC"> + <entry><constant>V4L2_PIX_FMT_H264_MVC</constant></entry> + <entry>'MVC'</entry> + <entry>H264 MVC video elementary stream.</entry> + </row> <row id="V4L2-PIX-FMT-H263"> <entry><constant>V4L2_PIX_FMT_H263</constant></entry> <entry>'H263'</entry> @@ -793,6 +798,11 @@ extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see <entry>'VC1L'</entry> <entry>VC1, SMPTE 421M Annex L compliant stream.</entry> </row> + <row id="V4L2-PIX-FMT-VP8"> + <entry><constant>V4L2_PIX_FMT_VP8</constant></entry> + <entry>'VP8'</entry> + <entry>VP8 video elementary stream.</entry> + </row> </tbody> </tgroup> </table> @@ -996,6 +1006,34 @@ the other bits are set to 0.</entry> <entry>Old 6-bit greyscale format. Only the most significant 6 bits of each byte are used, the other bits are set to 0.</entry> </row> + <row id="V4L2-PIX-FMT-S5C-UYVY-JPG"> + <entry><constant>V4L2_PIX_FMT_S5C_UYVY_JPG</constant></entry> + <entry>'S5CI'</entry> + <entry>Two-planar format used by Samsung S5C73MX cameras. The +first plane contains interleaved JPEG and UYVY image data, followed by meta data +in form of an array of offsets to the UYVY data blocks. The actual pointer array +follows immediately the interleaved JPEG/UYVY data, the number of entries in +this array equals the height of the UYVY image. Each entry is a 4-byte unsigned +integer in big endian order and it's an offset to a single pixel line of the +UYVY image. The first plane can start either with JPEG or UYVY data chunk. The +size of a single UYVY block equals the UYVY image's width multiplied by 2. The +size of a JPEG chunk depends on the image and can vary with each line. +<para>The second plane, at an offset of 4084 bytes, contains a 4-byte offset to +the pointer array in the first plane. This offset is followed by a 4-byte value +indicating size of the pointer array. All numbers in the second plane are also +in big endian order. Remaining data in the second plane is undefined. The +information in the second plane allows to easily find location of the pointer +array, which can be different for each frame. The size of the pointer array is +constant for given UYVY image height.</para> +<para>In order to extract UYVY and JPEG frames an application can initially set +a data pointer to the start of first plane and then add an offset from the first +entry of the pointers table. Such a pointer indicates start of an UYVY image +pixel line. Whole UYVY line can be copied to a separate buffer. These steps +should be repeated for each line, i.e. the number of entries in the pointer +array. Anything what's in between the UYVY lines is JPEG data and should be +concatenated to form the JPEG stream. </para> +</entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 49c532ebbbbe..a0a936455fae 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -2565,5 +2565,49 @@ </tgroup> </table> </section> + + <section id="v4l2-mbus-vendor-spec-fmts"> + <title>Vendor and Device Specific Formats</title> + + <note> + <title>Experimental</title> + <para>This is an <link linkend="experimental">experimental</link> +interface and may change in the future.</para> + </note> + + <para>This section lists complex data formats that are either vendor or + device specific. + </para> + + <para>The following table lists the existing vendor and device specific + formats.</para> + + <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-vendor-specific"> + <title>Vendor and device specific formats</title> + <tgroup cols="3"> + <colspec colname="id" align="left" /> + <colspec colname="code" align="left"/> + <colspec colname="remarks" align="left"/> + <thead> + <row> + <entry>Identifier</entry> + <entry>Code</entry> + <entry>Comments</entry> + </row> + </thead> + <tbody valign="top"> + <row id="V4L2-MBUS-FMT-S5C-UYVY-JPEG-1X8"> + <entry>V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8</entry> + <entry>0x5001</entry> + <entry> + Interleaved raw UYVY and JPEG image format with embedded + meta-data used by Samsung S3C73MX camera sensors. + </entry> + </row> + </tbody> + </tgroup> + </table> + </section> + </section> </section> diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml index 6a821a65a5ae..2d37abefce13 100644 --- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml @@ -121,8 +121,7 @@ remaining fields or returns an error code. The driver may also set field. It indicates a non-critical (recoverable) streaming error. In such case the application may continue as normal, but should be aware that data in the dequeued buffer might be corrupted. When using the multi-planar API, the -planes array does not have to be passed; the <structfield>m.planes</structfield> -member must be set to NULL in that case.</para> +planes array must be passed in as well.</para> <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the outgoing queue. When the diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml index 6e414d7b6df7..a597155c052d 100644 --- a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml @@ -48,8 +48,8 @@ <refsect1> <title>Description</title> - <para>This ioctl is part of the <link linkend="mmap">memory -mapping</link> I/O method. It can be used to query the status of a + <para>This ioctl is part of the <link linkend="mmap">streaming +</link> I/O method. It can be used to query the status of a buffer at any time after buffers have been allocated with the &VIDIOC-REQBUFS; ioctl.</para> @@ -71,6 +71,7 @@ the structure.</para> <para>In the <structfield>flags</structfield> field the <constant>V4L2_BUF_FLAG_MAPPED</constant>, +<constant>V4L2_BUF_FLAG_PREPARED</constant>, <constant>V4L2_BUF_FLAG_QUEUED</constant> and <constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The <structfield>memory</structfield> field will be set to the current @@ -79,8 +80,10 @@ contains the offset of the buffer from the start of the device memory, the <structfield>length</structfield> field its size. For the multi-planar API, fields <structfield>m.mem_offset</structfield> and <structfield>length</structfield> in the <structfield>m.planes</structfield> -array elements will be used instead. The driver may or may not set the remaining -fields and flags, they are meaningless in this context.</para> +array elements will be used instead and the <structfield>length</structfield> +field of &v4l2-buffer; is set to the number of filled-in array elements. +The driver may or may not set the remaining fields and flags, they are +meaningless in this context.</para> <para>The <structname>v4l2_buffer</structname> structure is specified in <xref linkend="buffer" />.</para> diff --git a/Documentation/arm/Booting b/Documentation/arm/Booting index a341d87d276e..0c1f475fdf36 100644 --- a/Documentation/arm/Booting +++ b/Documentation/arm/Booting @@ -154,13 +154,33 @@ In either case, the following conditions must be met: - CPU mode All forms of interrupts must be disabled (IRQs and FIQs) - The CPU must be in SVC mode. (A special exception exists for Angel) + + For CPUs which do not include the ARM virtualization extensions, the + CPU must be in SVC mode. (A special exception exists for Angel) + + CPUs which include support for the virtualization extensions can be + entered in HYP mode in order to enable the kernel to make full use of + these extensions. This is the recommended boot method for such CPUs, + unless the virtualisations are already in use by a pre-installed + hypervisor. + + If the kernel is not entered in HYP mode for any reason, it must be + entered in SVC mode. - Caches, MMUs The MMU must be off. Instruction cache may be on or off. Data cache must be off. + If the kernel is entered in HYP mode, the above requirements apply to + the HYP mode configuration in addition to the ordinary PL1 (privileged + kernel modes) configuration. In addition, all traps into the + hypervisor must be disabled, and PL1 access must be granted for all + peripherals and CPU resources for which this is architecturally + possible. Except for entering in HYP mode, the system configuration + should be such that a kernel which does not include support for the + virtualization extensions can boot correctly without extra help. + - The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image. diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt new file mode 100644 index 000000000000..b689a0d9441c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt @@ -0,0 +1,30 @@ +I2C for Atmel platforms + +Required properties : +- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c", + "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c" + or "atmel,at91sam9x5-i2c" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding + +Examples : + +i2c0: i2c@fff84000 { + compatible = "atmel,at91sam9g20-i2c"; + reg = <0xfff84000 0x100>; + interrupts = <12 4 6>; + #address-cells = <1>; + #size-cells = <0>; + + 24c512@50 { + compatible = "24c512"; + reg = <0x50>; + pagesize = <128>; + } +} diff --git a/Documentation/devicetree/bindings/i2c/davinci.txt b/Documentation/devicetree/bindings/i2c/davinci.txt new file mode 100644 index 000000000000..2dc935b4113d --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/davinci.txt @@ -0,0 +1,28 @@ +* Texas Instruments Davinci I2C + +This file provides information, what the device node for the +davinci i2c interface contain. + +Required properties: +- compatible: "ti,davinci-i2c"; +- reg : Offset and length of the register set for the device + +Recommended properties : +- interrupts : standard interrupt property. +- clock-frequency : desired I2C bus clock frequency in Hz. + +Example (enbw_cmc board): + i2c@1c22000 { + compatible = "ti,davinci-i2c"; + reg = <0x22000 0x1000>; + clock-frequency = <100000>; + interrupts = <15>; + interrupt-parent = <&intc>; + #address-cells = <1>; + #size-cells = <0>; + + dtt@48 { + compatible = "national,lm75"; + reg = <0x48>; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt index 30ac3a0557f7..7a3fe9e5f4cb 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt @@ -6,6 +6,7 @@ Required properties: - interrupts: Should contain ERROR and DMA interrupts - clock-frequency: Desired I2C bus clock frequency in Hz. Only 100000Hz and 400000Hz modes are supported. +- fsl,i2c-dma-channel: APBX DMA channel for the I2C Examples: @@ -16,4 +17,5 @@ i2c0: i2c@80058000 { reg = <0x80058000 2000>; interrupts = <111 68>; clock-frequency = <100000>; + fsl,i2c-dma-channel = <6>; }; diff --git a/Documentation/devicetree/bindings/i2c/nomadik.txt b/Documentation/devicetree/bindings/i2c/nomadik.txt new file mode 100644 index 000000000000..72065b0ff680 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nomadik.txt @@ -0,0 +1,23 @@ +I2C for Nomadik based systems + +Required (non-standard) properties: + - Nil + +Recommended (non-standard) properties: + - clock-frequency : Maximum bus clock frequency for the device + +Optional (non-standard) properties: + - Nil + +Example : + +i2c@80004000 { + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; + reg = <0x80004000 0x1000>; + interrupts = <0 21 0x4>; + #address-cells = <1>; + #size-cells = <0>; + v-i2c-supply = <&db8500_vape_reg>; + + clock-frequency = <400000>; +}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt index 548892c08c59..7da578d72123 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt @@ -7,7 +7,7 @@ as "armctrl" in the SoC documentation, hence naming of this binding. Required properties: -- compatible : should be "brcm,bcm2835-armctrl-ic.txt" +- compatible : should be "brcm,bcm2835-armctrl-ic" - reg : Specifies base physical address and size of the registers. - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an diff --git a/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt b/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt index 2de21c2acf55..844bd5fbd04c 100644 --- a/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt +++ b/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt @@ -7,7 +7,7 @@ free running counter values, and generates an interrupt. Required properties: -- compatible : should be "brcm,bcm2835-system-timer.txt" +- compatible : should be "brcm,bcm2835-system-timer" - reg : Specifies base physical address and size of the registers. - interrupts : A list of 4 interrupt sinks; one per timer channel. - clock-frequency : The frequency of the clock that drives the counter, in Hz. diff --git a/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt b/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt new file mode 100644 index 000000000000..56a96fb08a73 --- /dev/null +++ b/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt @@ -0,0 +1,41 @@ +Administrative interfaces for nfsd +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note that normally these interfaces are used only by the utilities in +nfs-utils. + +nfsd is controlled mainly by pseudofiles under the "nfsd" filesystem, +which is normally mounted at /proc/fs/nfsd/. + +The server is always started by the first write of a nonzero value to +nfsd/threads. + +Before doing that, NFSD can be told which sockets to listen on by +writing to nfsd/portlist; that write may be: + + - an ascii-encoded file descriptor, which should refer to a + bound (and listening, for tcp) socket, or + - "transportname port", where transportname is currently either + "udp", "tcp", or "rdma". + +If nfsd is started without doing any of these, then it will create one +udp and one tcp listener at port 2049 (see nfsd_init_socks). + +On startup, nfsd and lockd grace periods start. + +nfsd is shut down by a write of 0 to nfsd/threads. All locks and state +are thrown away at that point. + +Between startup and shutdown, the number of threads may be adjusted up +or down by additional writes to nfsd/threads or by writes to +nfsd/pool_threads. + +For more detail about files under nfsd/ and what they control, see +fs/nfsd/nfsctl.c; most of them have detailed comments. + +Implementation notes +^^^^^^^^^^^^^^^^^^^^ + +Note that the rpc server requires the caller to serialize addition and +removal of listening sockets, and startup and shutdown of the server. +For nfsd this is done using nfsd_mutex. diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas index 3a3079411a3d..da03146c182a 100644 --- a/Documentation/scsi/ChangeLog.megaraid_sas +++ b/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,3 +1,16 @@ +Release Date : Mon. Oct 1, 2012 17:00:00 PST 2012 - + (emaild-id:megaraidlinux@lsi.com) + Adam Radford +Current Version : 06.504.01.00-rc1 +Old Version : 00.00.06.18-rc1 + 1. Removed un-needed completion_lock spinlock calls. + 2. Add module param for configurable MSI-X vector count. + 3. Load io_request DataLength in bytes. + 4. Add array boundary check for SystemPD. + 5. Add SystemPD FastPath support. + 6. Remove duplicate code. + 7. Version, Changelog, Copyright update. +------------------------------------------------------------------------------- Release Date : Tue. Jun 17, 2012 17:00:00 PST 2012 - (emaild-id:megaraidlinux@lsi.com) Adam Radford/Kashyap Desai diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 54270df99d5c..cfe52c798d74 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -136,11 +136,25 @@ Or alternatively for integer menu controls, by calling v4l2_ctrl_new_int_menu: const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 def, const s64 *qmenu_int); +Standard menu controls with a driver specific menu are added by calling +v4l2_ctrl_new_std_menu_items: + + struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items( + struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 skip_mask, s32 def, const char * const *qmenu); + These functions are typically called right after the v4l2_ctrl_handler_init: static const s64 exp_bias_qmenu[] = { -2, -1, 0, 1, 2 }; + static const char * const test_pattern[] = { + "Disabled", + "Vertical Bars", + "Solid Black", + "Solid White", + }; v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls); v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops, @@ -156,6 +170,9 @@ These functions are typically called right after the v4l2_ctrl_handler_init: ARRAY_SIZE(exp_bias_qmenu) - 1, ARRAY_SIZE(exp_bias_qmenu) / 2 - 1, exp_bias_qmenu); + v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops, + V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0, + 0, test_pattern); ... if (foo->ctrl_handler.error) { int err = foo->ctrl_handler.error; @@ -185,6 +202,13 @@ v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and takes as the last argument an array of signed 64-bit integers that form an exact menu item list. +The v4l2_ctrl_new_std_menu_items function is very similar to +v4l2_ctrl_new_std_menu but takes an extra parameter qmenu, which is the driver +specific menu for an otherwise standard menu control. A good example for this +control is the test pattern control for capture/display/sensors devices that +have the capability to generate test patterns. These test patterns are hardware +specific, so the contents of the menu will vary from device to device. + Note that if something fails, the function will return NULL or an error and set ctrl_handler->error to the error code. If ctrl_handler->error was already set, then it will just return and do nothing. This is also true for diff --git a/MAINTAINERS b/MAINTAINERS index 0f6ff811da07..e73060fe0788 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1958,10 +1958,10 @@ S: Supported F: drivers/platform/x86/classmate-laptop.c COCCINELLE/Semantic Patches (SmPL) -M: Julia Lawall <julia@diku.dk> +M: Julia Lawall <Julia.Lawall@lip6.fr> M: Gilles Muller <Gilles.Muller@lip6.fr> -M: Nicolas Palix <npalix.work@gmail.com> -L: cocci@diku.dk (moderated for non-subscribers) +M: Nicolas Palix <nicolas.palix@imag.fr> +L: cocci@systeme.lip6.fr (moderated for non-subscribers) W: http://coccinelle.lip6.fr/ S: Supported F: scripts/coccinelle/ @@ -2423,11 +2423,6 @@ S: Maintained F: Documentation/hwmon/dme1737 F: drivers/hwmon/dme1737.c -DOCBOOK FOR DOCUMENTATION -M: Randy Dunlap <rdunlap@xenotime.net> -S: Maintained -F: scripts/kernel-doc - DOCKING STATION DRIVER M: Shaohua Li <shaohua.li@intel.com> L: linux-acpi@vger.kernel.org @@ -664,22 +664,9 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) endif # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments -# But warn user when we do so -warn-assign = \ -$(warning "WARNING: Appending $$K$(1) ($(K$(1))) from $(origin K$(1)) to kernel $$$(1)") - -ifneq ($(KCPPFLAGS),) - $(call warn-assign,CPPFLAGS) - KBUILD_CPPFLAGS += $(KCPPFLAGS) -endif -ifneq ($(KAFLAGS),) - $(call warn-assign,AFLAGS) - KBUILD_AFLAGS += $(KAFLAGS) -endif -ifneq ($(KCFLAGS),) - $(call warn-assign,CFLAGS) - KBUILD_CFLAGS += $(KCFLAGS) -endif +KBUILD_CPPFLAGS += $(KCPPFLAGS) +KBUILD_AFLAGS += $(KAFLAGS) +KBUILD_CFLAGS += $(KCFLAGS) # Use --build-id when available. LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\ diff --git a/arch/Kconfig b/arch/Kconfig index 26a28419cafc..a79a1ad8bb96 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -274,6 +274,9 @@ config ARCH_WANT_OLD_COMPAT_IPC config GENERIC_KERNEL_THREAD bool +config GENERIC_KERNEL_EXECVE + bool + config HAVE_ARCH_SECCOMP_FILTER bool help diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 7da91246e279..7a08cfb80ee8 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -21,6 +21,7 @@ config ALPHA select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE help The Alpha is a 64-bit general-purpose processor designed and marketed by the Digital Equipment Corporation of blessed memory, diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 28335bd40e40..4554ecbff7c6 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -84,7 +84,6 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) /* Work to do on interrupt/exception return. */ @@ -117,5 +116,7 @@ register struct thread_info *__current_thread_info __asm__("$8"); (int __user *)(value)); \ }) +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* __KERNEL__ */ #endif /* _ALPHA_THREAD_INFO_H */ diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 3cb6c1188984..7826e227e4d0 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -482,7 +482,6 @@ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_RT_SIGSUSPEND #define __ARCH_WANT_SYS_EXECVE -#define __ARCH_WANT_KERNEL_EXECVE /* "Conditional" syscalls. What we want is diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 7e43e1156d10..a7607832dd4f 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -311,7 +311,7 @@ entSys: .align 4 ret_from_sys_call: - cmovne $26, 0, $19 /* $19 = 0 => non-restartable */ + cmovne $26, 0, $18 /* $18 = 0 => non-restartable */ ldq $0, SP_OFF($sp) and $0, 8, $0 beq $0, ret_to_kernel @@ -320,8 +320,8 @@ ret_to_user: sampling and the rti. */ lda $16, 7 call_pal PAL_swpipl - ldl $5, TI_FLAGS($8) - and $5, _TIF_WORK_MASK, $2 + ldl $17, TI_FLAGS($8) + and $17, _TIF_WORK_MASK, $2 bne $2, work_pending restore_all: RESTORE_ALL @@ -341,10 +341,10 @@ $syscall_error: * frame to indicate that a negative return value wasn't an * error number.. */ - ldq $19, 0($sp) /* old syscall nr (zero if success) */ - beq $19, $ret_success + ldq $18, 0($sp) /* old syscall nr (zero if success) */ + beq $18, $ret_success - ldq $20, 72($sp) /* .. and this a3 */ + ldq $19, 72($sp) /* .. and this a3 */ subq $31, $0, $0 /* with error in v0 */ addq $31, 1, $1 /* set a3 for errno return */ stq $0, 0($sp) @@ -362,51 +362,35 @@ $ret_success: * Do all cleanup when returning from all interrupts and system calls. * * Arguments: - * $5: TI_FLAGS. * $8: current. - * $19: The old syscall number, or zero if this is not a return + * $17: TI_FLAGS. + * $18: The old syscall number, or zero if this is not a return * from a syscall that errored and is possibly restartable. - * $20: The old a3 value + * $19: The old a3 value */ .align 4 .ent work_pending work_pending: - and $5, _TIF_NEED_RESCHED, $2 - beq $2, $work_notifysig + and $17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING, $2 + bne $2, $work_notifysig $work_resched: - subq $sp, 16, $sp - stq $19, 0($sp) /* save syscall nr */ - stq $20, 8($sp) /* and error indication (a3) */ + /* + * We can get here only if we returned from syscall without SIGPENDING + * or got through work_notifysig already. Either case means no syscall + * restarts for us, so let $18 and $19 burn. + */ jsr $26, schedule - ldq $19, 0($sp) - ldq $20, 8($sp) - addq $sp, 16, $sp - /* Make sure need_resched and sigpending don't change between - sampling and the rti. */ - lda $16, 7 - call_pal PAL_swpipl - ldl $5, TI_FLAGS($8) - and $5, _TIF_WORK_MASK, $2 - beq $2, restore_all - and $5, _TIF_NEED_RESCHED, $2 - bne $2, $work_resched + mov 0, $18 + br ret_to_user $work_notifysig: mov $sp, $16 bsr $1, do_switch_stack - mov $sp, $17 - mov $5, $18 - mov $19, $9 /* save old syscall number */ - mov $20, $10 /* save old a3 */ - and $5, _TIF_SIGPENDING, $2 - cmovne $2, 0, $9 /* we don't want double syscall restarts */ - jsr $26, do_notify_resume - mov $9, $19 - mov $10, $20 + jsr $26, do_work_pending bsr $1, undo_switch_stack - br ret_to_user + br restore_all .end work_pending /* @@ -418,11 +402,10 @@ $work_notifysig: strace: /* set up signal stack, call syscall_trace */ bsr $1, do_switch_stack - jsr $26, syscall_trace + jsr $26, syscall_trace_enter /* returns the syscall number */ bsr $1, undo_switch_stack - /* get the system call number and the arguments back.. */ - ldq $0, 0($sp) + /* get the arguments back.. */ ldq $16, SP_OFF+24($sp) ldq $17, SP_OFF+32($sp) ldq $18, SP_OFF+40($sp) @@ -449,15 +432,15 @@ $strace_success: stq $0, 0($sp) /* save return value */ bsr $1, do_switch_stack - jsr $26, syscall_trace + jsr $26, syscall_trace_leave bsr $1, undo_switch_stack br $31, ret_from_sys_call .align 3 $strace_error: - ldq $19, 0($sp) /* old syscall nr (zero if success) */ - beq $19, $strace_success - ldq $20, 72($sp) /* .. and this a3 */ + ldq $18, 0($sp) /* old syscall nr (zero if success) */ + beq $18, $strace_success + ldq $19, 72($sp) /* .. and this a3 */ subq $31, $0, $0 /* with error in v0 */ addq $31, 1, $1 /* set a3 for errno return */ @@ -465,11 +448,11 @@ $strace_error: stq $1, 72($sp) /* a3 for return */ bsr $1, do_switch_stack - mov $19, $9 /* save old syscall number */ - mov $20, $10 /* save old a3 */ - jsr $26, syscall_trace - mov $9, $19 - mov $10, $20 + mov $18, $9 /* save old syscall number */ + mov $19, $10 /* save old a3 */ + jsr $26, syscall_trace_leave + mov $9, $18 + mov $10, $19 bsr $1, undo_switch_stack mov $31, $26 /* tell "ret_from_sys_call" we can restart */ @@ -620,24 +603,9 @@ ret_from_kernel_thread: mov $9, $27 mov $10, $16 jsr $26, ($9) - ldgp $gp, 0($26) - mov $0, $16 - mov $31, $26 - jmp $31, sys_exit -.end ret_from_kernel_thread - - .globl ret_from_kernel_execve - .align 4 - .ent ret_from_kernel_execve -ret_from_kernel_execve: - mov $16, $sp - /* Avoid the HAE being gratuitously wrong, to avoid restoring it. */ - ldq $2, alpha_mv+HAE_CACHE - stq $2, 152($sp) /* HAE */ mov $31, $19 /* to disable syscall restarts */ br $31, ret_to_user - -.end ret_from_kernel_execve +.end ret_from_kernel_thread /* @@ -698,7 +666,7 @@ sys_sigreturn: lda $sp, -SWITCH_STACK_SIZE($sp) jsr $26, do_sigreturn bne $9, 1f - jsr $26, syscall_trace + jsr $26, syscall_trace_leave 1: br $1, undo_switch_stack br ret_from_sys_call .end sys_sigreturn @@ -715,7 +683,7 @@ sys_rt_sigreturn: lda $sp, -SWITCH_STACK_SIZE($sp) jsr $26, do_rt_sigreturn bne $9, 1f - jsr $26, syscall_trace + jsr $26, syscall_trace_leave 1: br $1, undo_switch_stack br ret_from_sys_call .end sys_rt_sigreturn diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 63e77e3944ce..9eb090582cf1 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -449,7 +449,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) { int retval; struct cdfs_args tmp; - char *devname; + struct filename *devname; retval = -EFAULT; if (copy_from_user(&tmp, args, sizeof(tmp))) @@ -458,7 +458,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) retval = PTR_ERR(devname); if (IS_ERR(devname)) goto out; - retval = do_mount(devname, dirname, "ext2", flags, NULL); + retval = do_mount(devname->name, dirname, "ext2", flags, NULL); putname(devname); out: return retval; @@ -469,7 +469,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) { int retval; struct cdfs_args tmp; - char *devname; + struct filename *devname; retval = -EFAULT; if (copy_from_user(&tmp, args, sizeof(tmp))) @@ -478,7 +478,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) retval = PTR_ERR(devname); if (IS_ERR(devname)) goto out; - retval = do_mount(devname, dirname, "iso9660", flags, NULL); + retval = do_mount(devname->name, dirname, "iso9660", flags, NULL); putname(devname); out: return retval; @@ -499,7 +499,7 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, int, flag, void __user *, data) { int retval; - char *name; + struct filename *name; name = getname(path); retval = PTR_ERR(name); @@ -507,13 +507,13 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, goto out; switch (typenr) { case 1: - retval = osf_ufs_mount(name, data, flag); + retval = osf_ufs_mount(name->name, data, flag); break; case 6: - retval = osf_cdfs_mount(name, data, flag); + retval = osf_cdfs_mount(name->name, data, flag); break; case 9: - retval = osf_procfs_mount(name, data, flag); + retval = osf_procfs_mount(name->name, data, flag); break; default: retval = -EINVAL; diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 54616f496aed..2a4a80ff4a20 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -13,6 +13,7 @@ #include <linux/user.h> #include <linux/security.h> #include <linux/signal.h> +#include <linux/tracehook.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -312,25 +313,18 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } +asmlinkage unsigned long syscall_trace_enter(void) +{ + unsigned long ret = 0; + if (test_thread_flag(TIF_SYSCALL_TRACE) && + tracehook_report_syscall_entry(current_pt_regs())) + ret = -1UL; + return ret ?: current_pt_regs()->r0; +} + asmlinkage void -syscall_trace(void) +syscall_trace_leave(void) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - if (!(current->ptrace & PT_PTRACED)) - return; - /* The 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * This isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(current_pt_regs(), 0); } diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index a8c97d42ec8e..32575f85507d 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -298,8 +298,9 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, - struct switch_stack *sw, unsigned long mask, unsigned long sp) + unsigned long mask, unsigned long sp) { + struct switch_stack *sw = (struct switch_stack *)regs - 1; long i, err = 0; err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); @@ -354,7 +355,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, - struct pt_regs *regs, struct switch_stack * sw) + struct pt_regs *regs) { unsigned long oldsp, r26, err = 0; struct sigframe __user *frame; @@ -364,7 +365,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return -EFAULT; - err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); + err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp); if (err) return -EFAULT; @@ -401,7 +402,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) + sigset_t *set, struct pt_regs *regs) { unsigned long oldsp, r26, err = 0; struct rt_sigframe __user *frame; @@ -420,7 +421,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], oldsp); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) @@ -464,15 +465,15 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, */ static inline void handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, - struct pt_regs * regs, struct switch_stack *sw) + struct pt_regs * regs) { sigset_t *oldset = sigmask_to_save(); int ret; if (ka->sa.sa_flags & SA_SIGINFO) - ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); + ret = setup_rt_frame(sig, ka, info, oldset, regs); else - ret = setup_frame(sig, ka, oldset, regs, sw); + ret = setup_frame(sig, ka, oldset, regs); if (ret) { force_sigsegv(sig, current); @@ -519,8 +520,7 @@ syscall_restart(unsigned long r0, unsigned long r19, * all (if we get here from anything but a syscall return, it will be 0) */ static void -do_signal(struct pt_regs * regs, struct switch_stack * sw, - unsigned long r0, unsigned long r19) +do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) { siginfo_t info; int signr; @@ -537,7 +537,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, /* Whee! Actually deliver the signal. */ if (r0) syscall_restart(r0, r19, regs, &ka); - handle_signal(signr, &ka, &info, regs, sw); + handle_signal(signr, &ka, &info, regs); if (single_stepping) ptrace_set_bpt(current); /* re-set bpt */ return; @@ -568,15 +568,23 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, } void -do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, - unsigned long thread_info_flags, +do_work_pending(struct pt_regs *regs, unsigned long thread_flags, unsigned long r0, unsigned long r19) { - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs, sw, r0, r19); - - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + do { + if (thread_flags & _TIF_NEED_RESCHED) { + schedule(); + } else { + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + do_signal(regs, r0, r19); + r0 = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e40eefb5d32d..431c3753145a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -53,6 +53,7 @@ config ARM select GENERIC_STRNLEN_USER select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -494,7 +495,6 @@ config ARCH_IOP32X depends on MMU select CPU_XSCALE select NEED_MACH_GPIO_H - select NEED_MACH_IO_H select NEED_RET_TO_USER select PLAT_IOP select PCI @@ -508,7 +508,6 @@ config ARCH_IOP33X depends on MMU select CPU_XSCALE select NEED_MACH_GPIO_H - select NEED_MACH_IO_H select NEED_RET_TO_USER select PLAT_IOP select PCI @@ -1772,6 +1771,7 @@ source "mm/Kconfig" config FORCE_MAX_ZONEORDER int "Maximum zone order" if ARCH_SHMOBILE range 11 64 if ARCH_SHMOBILE + default "12" if SOC_AM33XX default "9" if SA1111 default "11" help diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore index d0d441c429ae..f79a08efe000 100644 --- a/arch/arm/boot/compressed/.gitignore +++ b/arch/arm/boot/compressed/.gitignore @@ -1,6 +1,7 @@ ashldi3.S font.c lib1funcs.S +hyp-stub.S piggy.gzip piggy.lzo piggy.lzma diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index bb267562e7ed..a517153a13ea 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -30,6 +30,10 @@ FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c OBJS += string.o CFLAGS_string.o := -Os +ifeq ($(CONFIG_ARM_VIRT_EXT),y) +OBJS += hyp-stub.o +endif + # # Architecture dependencies # @@ -126,7 +130,7 @@ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) endif ccflags-y := -fpic -fno-builtin -I$(obj) -asflags-y := -Wa,-march=all +asflags-y := -Wa,-march=all -DZIMAGE # Supply kernel BSS size to the decompressor via a linker symbol. KBSS_SZ = $(shell $(CROSS_COMPILE)size $(obj)/../../../../vmlinux | \ @@ -198,3 +202,6 @@ $(obj)/font.c: $(FONTC) $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) @sed "$(SEDFLAGS)" < $< > $@ + +$(obj)/hyp-stub.S: $(srctree)/arch/$(SRCARCH)/kernel/hyp-stub.S + $(call cmd,shipped) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index bc67cbff3944..90275f036cd1 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ #include <linux/linkage.h> +#include <asm/assembler.h> /* * Debugging stuff @@ -132,7 +133,12 @@ start: .word start @ absolute load/run zImage address .word _edata @ zImage end address THUMB( .thumb ) -1: mov r7, r1 @ save architecture ID +1: + mrs r9, cpsr +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install @ get into SVC mode, reversibly +#endif + mov r7, r1 @ save architecture ID mov r8, r2 @ save atags pointer #ifndef __ARM_ARCH_2__ @@ -148,9 +154,9 @@ start: ARM( swi 0x123456 ) @ angel_SWI_ARM THUMB( svc 0xab ) @ angel_SWI_THUMB not_angel: - mrs r2, cpsr @ turn off interrupts to - orr r2, r2, #0xc0 @ prevent angel from running - msr cpsr_c, r2 + safe_svcmode_maskall r0 + msr spsr_cxsf, r9 @ Save the CPU boot mode in + @ SPSR #else teqp pc, #0x0c000003 @ turn off interrupts #endif @@ -350,6 +356,20 @@ dtb_check_done: adr r5, restart bic r5, r5, #31 +/* Relocate the hyp vector base if necessary */ +#ifdef CONFIG_ARM_VIRT_EXT + mrs r0, spsr + and r0, r0, #MODE_MASK + cmp r0, #HYP_MODE + bne 1f + + bl __hyp_get_vectors + sub r0, r0, r5 + add r0, r0, r10 + bl __hyp_set_vectors +1: +#endif + sub r9, r6, r5 @ size to copy add r9, r9, #31 @ rounded up to a multiple bic r9, r9, #31 @ ... of 32 bytes @@ -458,11 +478,29 @@ not_relocated: mov r0, #0 bl decompress_kernel bl cache_clean_flush bl cache_off - mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer - ARM( mov pc, r4 ) @ call kernel - THUMB( bx r4 ) @ entry point is always ARM + +#ifdef CONFIG_ARM_VIRT_EXT + mrs r0, spsr @ Get saved CPU boot mode + and r0, r0, #MODE_MASK + cmp r0, #HYP_MODE @ if not booted in HYP mode... + bne __enter_kernel @ boot kernel directly + + adr r12, .L__hyp_reentry_vectors_offset + ldr r0, [r12] + add r0, r0, r12 + + bl __hyp_set_vectors + __HVC(0) @ otherwise bounce to hyp mode + + b . @ should never be reached + + .align 2 +.L__hyp_reentry_vectors_offset: .long __hyp_reentry_vectors - . +#else + b __enter_kernel +#endif .align 2 .type LC0, #object @@ -1196,6 +1234,25 @@ memdump: mov r12, r0 #endif .ltorg + +#ifdef CONFIG_ARM_VIRT_EXT +.align 5 +__hyp_reentry_vectors: + W(b) . @ reset + W(b) . @ undef + W(b) . @ svc + W(b) . @ pabort + W(b) . @ dabort + W(b) __enter_kernel @ hyp + W(b) . @ irq + W(b) . @ fiq +#endif /* CONFIG_ARM_VIRT_EXT */ + +__enter_kernel: + mov r0, #0 @ must be 0 + ARM( mov pc, r4 ) @ call kernel + THUMB( bx r4 ) @ entry point is always ARM + reloc_code_end: .align diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 29f541f0e653..c1ce813fcc4a 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -25,14 +25,6 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \ exynos4210-trats.dtb \ exynos5250-smdk5250.dtb dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb -dtb-$(CONFIG_ARCH_IMX5) += imx51-babbage.dtb \ - imx53-ard.dtb \ - imx53-evk.dtb \ - imx53-qsb.dtb \ - imx53-smd.dtb -dtb-$(CONFIG_SOC_IMX6Q) += imx6q-arm2.dtb \ - imx6q-sabrelite.dtb \ - imx6q-sabresd.dtb dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \ kirkwood-dns325.dtb \ @@ -76,7 +68,9 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap4-pandaES.dtb \ omap4-var_som.dtb \ omap4-sdp.dtb \ - omap5-evm.dtb + omap5-evm.dtb \ + am335x-evm.dtb \ + am335x-bone.dtb dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb dtb-$(CONFIG_ARCH_U8500) += snowball.dtb dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \ @@ -104,5 +98,8 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ vexpress-v2p-ca15-tc1.dtb \ vexpress-v2p-ca15_a7.dtb \ xenvm-4.2.dtb +dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ + wm8505-ref.dtb \ + wm8650-mid.dtb endif diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 7c95f76398de..d410581a5a85 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -28,6 +28,7 @@ gpio2 = &pioC; tcb0 = &tcb0; tcb1 = &tcb1; + i2c0 = &i2c0; }; cpus { cpu@0 { @@ -202,6 +203,15 @@ status = "disabled"; }; + i2c0: i2c@fffac000 { + compatible = "atmel,at91sam9260-i2c"; + reg = <0xfffac000 0x100>; + interrupts = <11 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + adc0: adc@fffe0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffe0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 195019b7ca0e..3e6e5c1abbf3 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -24,6 +24,7 @@ gpio3 = &pioD; gpio4 = &pioE; tcb0 = &tcb0; + i2c0 = &i2c0; }; cpus { cpu@0 { @@ -185,6 +186,15 @@ interrupts = <24 4 2>; status = "disabled"; }; + + i2c0: i2c@fff88000 { + compatible = "atmel,at91sam9263-i2c"; + reg = <0xfff88000 0x100>; + interrupts = <13 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi index 2a1d1ca8bd86..75ce6e760016 100644 --- a/arch/arm/boot/dts/at91sam9g20.dtsi +++ b/arch/arm/boot/dts/at91sam9g20.dtsi @@ -18,6 +18,10 @@ ahb { apb { + i2c0: i2c@fffac000 { + compatible = "atmel,at91sam9g20-i2c"; + }; + adc0: adc@fffe0000 { atmel,adc-startup-time = <40>; }; diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts index 96514c134e54..877c08f06763 100644 --- a/arch/arm/boot/dts/at91sam9g25ek.dts +++ b/arch/arm/boot/dts/at91sam9g25ek.dts @@ -32,6 +32,18 @@ phy-mode = "rmii"; status = "okay"; }; + + i2c0: i2c@f8010000 { + status = "okay"; + }; + + i2c1: i2c@f8014000 { + status = "okay"; + }; + + i2c2: i2c@f8018000 { + status = "okay"; + }; }; usb0: ohci@00600000 { diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 63751b1e744b..3add030d61f8 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -29,6 +29,8 @@ gpio4 = &pioE; tcb0 = &tcb0; tcb1 = &tcb1; + i2c0 = &i2c0; + i2c1 = &i2c1; }; cpus { cpu@0 { @@ -206,6 +208,24 @@ status = "disabled"; }; + i2c0: i2c@fff84000 { + compatible = "atmel,at91sam9g10-i2c"; + reg = <0xfff84000 0x100>; + interrupts = <12 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@fff88000 { + compatible = "atmel,at91sam9g10-i2c"; + reg = <0xfff88000 0x100>; + interrupts = <13 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + adc0: adc@fffb0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffb0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index a3633bd13111..15e1dd43f625 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -46,6 +46,14 @@ phy-mode = "rmii"; status = "okay"; }; + + i2c0: i2c@fff84000 { + status = "okay"; + }; + + i2c1: i2c@fff88000 { + status = "okay"; + }; }; nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index ef9336ae9614..82508d68aa7e 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -26,6 +26,8 @@ gpio3 = &pioD; tcb0 = &tcb0; tcb1 = &tcb1; + i2c0 = &i2c0; + i2c1 = &i2c1; }; cpus { cpu@0 { @@ -182,6 +184,24 @@ atmel,use-dma-tx; status = "disabled"; }; + + i2c0: i2c@f8010000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8010000 0x100>; + interrupts = <9 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@f8014000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8014000 0x100>; + interrupts = <10 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index f4e43e38f3a1..912b2c283d6f 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -37,6 +37,14 @@ dbgu: serial@fffff200 { status = "okay"; }; + + i2c0: i2c@f8010000 { + status = "okay"; + }; + + i2c1: i2c@f8014000 { + status = "okay"; + }; }; nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 8a387a8d61b7..03fc136421c5 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -27,6 +27,9 @@ gpio3 = &pioD; tcb0 = &tcb0; tcb1 = &tcb1; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; }; cpus { cpu@0 { @@ -196,6 +199,33 @@ status = "disabled"; }; + i2c0: i2c@f8010000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8010000 0x100>; + interrupts = <9 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@f8014000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8014000 0x100>; + interrupts = <10 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@f8018000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8018000 0x100>; + interrupts = <11 4 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + adc0: adc@f804c000 { compatible = "atmel,at91sam9260-adc"; reg = <0xf804c000 0x100>; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 59fbfba23df8..e16d63155480 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -764,6 +764,7 @@ reg = <0x80058000 0x2000>; interrupts = <111 68>; clock-frequency = <100000>; + fsl,i2c-dma-channel = <6>; status = "disabled"; }; @@ -774,6 +775,7 @@ reg = <0x8005a000 0x2000>; interrupts = <110 69>; clock-frequency = <100000>; + fsl,i2c-dma-channel = <7>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts index 20b966ee1bb3..e8f927cbb376 100644 --- a/arch/arm/boot/dts/omap4-panda.dts +++ b/arch/arm/boot/dts/omap4-panda.dts @@ -59,6 +59,41 @@ }; }; +&omap4_pmx_core { + pinctrl-names = "default"; + pinctrl-0 = < + &twl6040_pins + &mcpdm_pins + &mcbsp1_pins + >; + + twl6040_pins: pinmux_twl6040_pins { + pinctrl-single,pins = < + 0xe0 0x3 /* hdq_sio.gpio_127 OUTPUT | MODE3 */ + 0x160 0x100 /* sys_nirq2.sys_nirq2 INPUT | MODE0 */ + >; + }; + + mcpdm_pins: pinmux_mcpdm_pins { + pinctrl-single,pins = < + 0xc6 0x108 /* abe_pdm_ul_data.abe_pdm_ul_data INPUT PULLDOWN | MODE0 */ + 0xc8 0x108 /* abe_pdm_dl_data.abe_pdm_dl_data INPUT PULLDOWN | MODE0 */ + 0xca 0x118 /* abe_pdm_frame.abe_pdm_frame INPUT PULLUP | MODE0 */ + 0xcc 0x108 /* abe_pdm_lb_clk.abe_pdm_lb_clk INPUT PULLDOWN | MODE0 */ + 0xce 0x108 /* abe_clks.abe_clks INPUT PULLDOWN | MODE0 */ + >; + }; + + mcbsp1_pins: pinmux_mcbsp1_pins { + pinctrl-single,pins = < + 0xbe 0x100 /* abe_mcbsp1_clkx.abe_mcbsp1_clkx INPUT | MODE0 */ + 0xc0 0x108 /* abe_mcbsp1_dr.abe_mcbsp1_dr INPUT PULLDOWN | MODE0 */ + 0xc2 0x8 /* abe_mcbsp1_dx.abe_mcbsp1_dx OUTPUT PULLDOWN | MODE0 */ + 0xc4 0x100 /* abe_mcbsp1_fsx.abe_mcbsp1_fsx INPUT | MODE0 */ + >; + }; +}; + &i2c1 { clock-frequency = <400000>; @@ -137,3 +172,15 @@ cs1-used; device-handle = <&elpida_ECB240ABACN>; }; + +&mcbsp2 { + status = "disabled"; +}; + +&mcbsp3 { + status = "disabled"; +}; + +&dmic { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 94a23b39033d..5b7e04fbff50 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -117,6 +117,15 @@ }; &omap4_pmx_core { + pinctrl-names = "default"; + pinctrl-0 = < + &twl6040_pins + &mcpdm_pins + &dmic_pins + &mcbsp1_pins + &mcbsp2_pins + >; + uart2_pins: pinmux_uart2_pins { pinctrl-single,pins = < 0xd8 0x118 /* uart2_cts.uart2_cts INPUT_PULLUP | MODE0 */ @@ -141,6 +150,50 @@ 0x11e 0 /* uart4_tx.uart4_tx OUTPUT | MODE0 */ >; }; + + twl6040_pins: pinmux_twl6040_pins { + pinctrl-single,pins = < + 0xe0 0x3 /* hdq_sio.gpio_127 OUTPUT | MODE3 */ + 0x160 0x100 /* sys_nirq2.sys_nirq2 INPUT | MODE0 */ + >; + }; + + mcpdm_pins: pinmux_mcpdm_pins { + pinctrl-single,pins = < + 0xc6 0x108 /* abe_pdm_ul_data.abe_pdm_ul_data INPUT PULLDOWN | MODE0 */ + 0xc8 0x108 /* abe_pdm_dl_data.abe_pdm_dl_data INPUT PULLDOWN | MODE0 */ + 0xca 0x118 /* abe_pdm_frame.abe_pdm_frame INPUT PULLUP | MODE0 */ + 0xcc 0x108 /* abe_pdm_lb_clk.abe_pdm_lb_clk INPUT PULLDOWN | MODE0 */ + 0xce 0x108 /* abe_clks.abe_clks INPUT PULLDOWN | MODE0 */ + >; + }; + + dmic_pins: pinmux_dmic_pins { + pinctrl-single,pins = < + 0xd0 0 /* abe_dmic_clk1.abe_dmic_clk1 OUTPUT | MODE0 */ + 0xd2 0x100 /* abe_dmic_din1.abe_dmic_din1 INPUT | MODE0 */ + 0xd4 0x100 /* abe_dmic_din2.abe_dmic_din2 INPUT | MODE0 */ + 0xd6 0x100 /* abe_dmic_din3.abe_dmic_din3 INPUT | MODE0 */ + >; + }; + + mcbsp1_pins: pinmux_mcbsp1_pins { + pinctrl-single,pins = < + 0xbe 0x100 /* abe_mcbsp1_clkx.abe_mcbsp1_clkx INPUT | MODE0 */ + 0xc0 0x108 /* abe_mcbsp1_dr.abe_mcbsp1_dr INPUT PULLDOWN | MODE0 */ + 0xc2 0x8 /* abe_mcbsp1_dx.abe_mcbsp1_dx OUTPUT PULLDOWN | MODE0 */ + 0xc4 0x100 /* abe_mcbsp1_fsx.abe_mcbsp1_fsx INPUT | MODE0 */ + >; + }; + + mcbsp2_pins: pinmux_mcbsp2_pins { + pinctrl-single,pins = < + 0xb6 0x100 /* abe_mcbsp2_clkx.abe_mcbsp2_clkx INPUT | MODE0 */ + 0xb8 0x108 /* abe_mcbsp2_dr.abe_mcbsp2_dr INPUT PULLDOWN | MODE0 */ + 0xba 0x8 /* abe_mcbsp2_dx.abe_mcbsp2_dx OUTPUT PULLDOWN | MODE0 */ + 0xbc 0x100 /* abe_mcbsp2_fsx.abe_mcbsp2_fsx INPUT | MODE0 */ + >; + }; }; &i2c1 { @@ -349,3 +402,7 @@ pinctrl-names = "default"; pinctrl-0 = <&uart4_pins>; }; + +&mcbsp3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/omap5-evm.dts b/arch/arm/boot/dts/omap5-evm.dts index 9c41a3f311aa..c663eba73168 100644 --- a/arch/arm/boot/dts/omap5-evm.dts +++ b/arch/arm/boot/dts/omap5-evm.dts @@ -27,6 +27,60 @@ }; +&omap5_pmx_core { + pinctrl-names = "default"; + pinctrl-0 = < + &twl6040_pins + &mcpdm_pins + &dmic_pins + &mcbsp1_pins + &mcbsp2_pins + >; + + twl6040_pins: pinmux_twl6040_pins { + pinctrl-single,pins = < + 0x18a 0x6 /* perslimbus2_clock.gpio5_145 OUTPUT | MODE6 */ + >; + }; + + mcpdm_pins: pinmux_mcpdm_pins { + pinctrl-single,pins = < + 0x142 0x108 /* abe_clks.abe_clks INPUT PULLDOWN | MODE0 */ + 0x15c 0x108 /* abemcpdm_ul_data.abemcpdm_ul_data INPUT PULLDOWN | MODE0 */ + 0x15e 0x108 /* abemcpdm_dl_data.abemcpdm_dl_data INPUT PULLDOWN | MODE0 */ + 0x160 0x118 /* abemcpdm_frame.abemcpdm_frame INPUT PULLUP | MODE0 */ + 0x162 0x108 /* abemcpdm_lb_clk.abemcpdm_lb_clk INPUT PULLDOWN | MODE0 */ + >; + }; + + dmic_pins: pinmux_dmic_pins { + pinctrl-single,pins = < + 0x144 0x100 /* abedmic_din1.abedmic_din1 INPUT | MODE0 */ + 0x146 0x100 /* abedmic_din2.abedmic_din2 INPUT | MODE0 */ + 0x148 0x100 /* abedmic_din3.abedmic_din3 INPUT | MODE0 */ + 0x14a 0 /* abedmic_clk1.abedmic_clk1 OUTPUT | MODE0 */ + >; + }; + + mcbsp1_pins: pinmux_mcbsp1_pins { + pinctrl-single,pins = < + 0x14c 0x101 /* abedmic_clk2.abemcbsp1_fsx INPUT | MODE1 */ + 0x14e 0x9 /* abedmic_clk3.abemcbsp1_dx OUTPUT PULLDOWN | MODE1 */ + 0x150 0x101 /* abeslimbus1_clock.abemcbsp1_clkx INPUT | MODE0 */ + 0x152 0x109 /* abeslimbus1_data.abemcbsp1_dr INPUT PULLDOWN | MODE1 */ + >; + }; + + mcbsp2_pins: pinmux_mcbsp2_pins { + pinctrl-single,pins = < + 0x154 0x108 /* abemcbsp2_dr.abemcbsp2_dr INPUT PULLDOWN | MODE0 */ + 0x156 0x8 /* abemcbsp2_dx.abemcbsp2_dx OUTPUT PULLDOWN | MODE0 */ + 0x158 0x100 /* abemcbsp2_fsx.abemcbsp2_fsx INPUT | MODE0 */ + 0x15a 0x100 /* abemcbsp2_clkx.abemcbsp2_clkx INPUT | MODE0 */ + >; + }; +}; + &mmc1 { vmmc-supply = <&vmmcsd_fixed>; bus-width = <4>; @@ -82,3 +136,7 @@ 0x020700d9>; /* SEARCH */ linux,input-no-autorepeat; }; + +&mcbsp3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 5db33f481a33..42c78beb4fdc 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -77,6 +77,23 @@ ranges; ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; + omap5_pmx_core: pinmux@4a002840 { + compatible = "ti,omap4-padconf", "pinctrl-single"; + reg = <0x4a002840 0x01b6>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0x7fff>; + }; + omap5_pmx_wkup: pinmux@4ae0c840 { + compatible = "ti,omap4-padconf", "pinctrl-single"; + reg = <0x4ae0c840 0x0038>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0x7fff>; + }; + gic: interrupt-controller@48211000 { compatible = "arm,cortex-a15-gic"; interrupt-controller; diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index e60dc7124e92..f0ba901676ac 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -539,7 +539,7 @@ nvidia,invert-interrupt; }; - memory-controller@0x7000f400 { + memory-controller@7000f400 { emc-table@190000 { reg = <190000>; compatible = "nvidia,tegra20-emc-table"; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 67a6cd910b96..f3a09d0d45bc 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -170,7 +170,7 @@ reg = <0x7000e400 0x400>; }; - memory-controller@0x7000f000 { + memory-controller@7000f000 { compatible = "nvidia,tegra20-mc"; reg = <0x7000f000 0x024 0x7000f03c 0x3c4>; @@ -183,7 +183,7 @@ 0x58000000 0x02000000>; /* GART aperture */ }; - memory-controller@0x7000f400 { + memory-controller@7000f400 { compatible = "nvidia,tegra20-emc"; reg = <0x7000f400 0x200>; #address-cells = <1>; diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index c4110d1b1f2d..001f4913799c 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -284,11 +284,17 @@ int dma_set_coherent_mask(struct device *dev, u64 mask) int __init it8152_pci_setup(int nr, struct pci_sys_data *sys) { - it8152_io.start = IT8152_IO_BASE + 0x12000; - it8152_io.end = IT8152_IO_BASE + 0x12000 + 0x100000; + /* + * FIXME: use pci_ioremap_io to remap the IO space here and + * move over to the generic io.h implementation. + * This requires solving the same problem for PXA PCMCIA + * support. + */ + it8152_io.start = (unsigned long)IT8152_IO_BASE + 0x12000; + it8152_io.end = (unsigned long)IT8152_IO_BASE + 0x12000 + 0x100000; sys->mem_offset = 0x10000000; - sys->io_offset = IT8152_IO_BASE; + sys->io_offset = (unsigned long)IT8152_IO_BASE; if (request_resource(&ioport_resource, &it8152_io)) { printk(KERN_ERR "PCI: unable to allocate IO region\n"); diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 5c8b3bf4d825..2ef95813fce0 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -22,6 +22,7 @@ #include <asm/ptrace.h> #include <asm/domain.h> +#include <asm/opcodes-virt.h> #define IOMEM(x) (x) @@ -240,6 +241,34 @@ #endif /* + * Helper macro to enter SVC mode cleanly and mask interrupts. reg is + * a scratch register for the macro to overwrite. + * + * This macro is intended for forcing the CPU into SVC mode at boot time. + * you cannot return to the original mode. + * + * Beware, it also clobers LR. + */ +.macro safe_svcmode_maskall reg:req + mrs \reg , cpsr + mov lr , \reg + and lr , lr , #MODE_MASK + cmp lr , #HYP_MODE + orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT + bic \reg , \reg , #MODE_MASK + orr \reg , \reg , #SVC_MODE +THUMB( orr \reg , \reg , #PSR_T_BIT ) + bne 1f + orr \reg, \reg, #PSR_A_BIT + adr lr, BSYM(2f) + msr spsr_cxsf, \reg + __MSR_ELR_HYP(14) + __ERET +1: msr cpsr_c, \reg +2: +.endm + +/* * STRT/LDRT access macros with ARM and Thumb-2 variants */ #ifdef CONFIG_THUMB2_KERNEL diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index e4448e16046d..e1489c54cd12 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -49,6 +49,13 @@ * * Unconditionally clean and invalidate the entire cache. * + * flush_kern_louis() + * + * Flush data cache levels up to the level of unification + * inner shareable and invalidate the I-cache. + * Only needed from v7 onwards, falls back to flush_cache_all() + * for all other processor versions. + * * flush_user_all() * * Clean and invalidate all user space cache entries @@ -97,6 +104,7 @@ struct cpu_cache_fns { void (*flush_icache_all)(void); void (*flush_kern_all)(void); + void (*flush_kern_louis)(void); void (*flush_user_all)(void); void (*flush_user_range)(unsigned long, unsigned long, unsigned int); @@ -119,6 +127,7 @@ extern struct cpu_cache_fns cpu_cache; #define __cpuc_flush_icache_all cpu_cache.flush_icache_all #define __cpuc_flush_kern_all cpu_cache.flush_kern_all +#define __cpuc_flush_kern_louis cpu_cache.flush_kern_louis #define __cpuc_flush_user_all cpu_cache.flush_user_all #define __cpuc_flush_user_range cpu_cache.flush_user_range #define __cpuc_coherent_kern_range cpu_cache.coherent_kern_range @@ -139,6 +148,7 @@ extern struct cpu_cache_fns cpu_cache; extern void __cpuc_flush_icache_all(void); extern void __cpuc_flush_kern_all(void); +extern void __cpuc_flush_kern_louis(void); extern void __cpuc_flush_user_all(void); extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); extern void __cpuc_coherent_kern_range(unsigned long, unsigned long); @@ -204,6 +214,11 @@ static inline void __flush_icache_all(void) __flush_icache_preferred(); } +/* + * Flush caches up to Level of Unification Inner Shareable + */ +#define flush_cache_louis() __cpuc_flush_kern_louis() + #define flush_cache_all() __cpuc_flush_kern_all() static inline void vivt_flush_cache_mm(struct mm_struct *mm) diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index 4f8d2c0dc441..cca9f15704ed 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -132,6 +132,7 @@ #ifndef MULTI_CACHE #define __cpuc_flush_icache_all __glue(_CACHE,_flush_icache_all) #define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all) +#define __cpuc_flush_kern_louis __glue(_CACHE,_flush_kern_cache_louis) #define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all) #define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range) #define __cpuc_coherent_kern_range __glue(_CACHE,_coherent_kern_range) diff --git a/arch/arm/include/asm/opcodes-virt.h b/arch/arm/include/asm/opcodes-virt.h index b85665a96f8e..efcfdf92d9d5 100644 --- a/arch/arm/include/asm/opcodes-virt.h +++ b/arch/arm/include/asm/opcodes-virt.h @@ -26,4 +26,14 @@ 0xF7E08000 | (((imm16) & 0xF000) << 4) | ((imm16) & 0x0FFF) \ ) +#define __ERET __inst_arm_thumb32( \ + 0xE160006E, \ + 0xF3DE8F00 \ +) + +#define __MSR_ELR_HYP(regnum) __inst_arm_thumb32( \ + 0xE12EF300 | regnum, \ + 0xF3808E30 | (regnum << 16) \ +) + #endif /* ! __ASM_ARM_OPCODES_VIRT_H */ diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 44fe998269d9..142d6ae41231 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -44,6 +44,7 @@ #define IRQ_MODE 0x00000012 #define SVC_MODE 0x00000013 #define ABT_MODE 0x00000017 +#define HYP_MODE 0x0000001a #define UND_MODE 0x0000001b #define SYSTEM_MODE 0x0000001f #define MODE32_BIT 0x00000010 diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index f71cdab18b87..8477b4c1d39f 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -151,7 +151,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 #define TIF_SYSCALL_TRACEPOINT 10 -#define TIF_POLLING_NRFLAG 16 #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20 @@ -164,7 +163,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) -#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index f259921edfe9..91819ad54424 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -479,7 +479,6 @@ #define __ARCH_WANT_SYS_SOCKETCALL #endif #define __ARCH_WANT_SYS_EXECVE -#define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index a7aadbd9a6dd..6a6f1e485f41 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h @@ -28,7 +28,7 @@ ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] tst \tmp, #HWCAP_VFPv3D16 - ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} + ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} addne \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 @@ -52,7 +52,7 @@ ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] tst \tmp, #HWCAP_VFPv3D16 - stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} + stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} addne \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h new file mode 100644 index 000000000000..86164df86cb4 --- /dev/null +++ b/arch/arm/include/asm/virt.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 Linaro Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef VIRT_H +#define VIRT_H + +#include <asm/ptrace.h> + +/* + * Flag indicating that the kernel was not entered in the same mode on every + * CPU. The zImage loader stashes this value in an SPSR, so we need an + * architecturally defined flag bit here (the N flag, as it happens) + */ +#define BOOT_CPU_MODE_MISMATCH (1<<31) + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_ARM_VIRT_EXT +/* + * __boot_cpu_mode records what mode the primary CPU was booted in. + * A correctly-implemented bootloader must start all CPUs in the same mode: + * if it fails to do this, the flag BOOT_CPU_MODE_MISMATCH is set to indicate + * that some CPU(s) were booted in a different mode. + * + * This allows the kernel to flag an error when the secondaries have come up. + */ +extern int __boot_cpu_mode; + +void __hyp_set_vectors(unsigned long phys_vector_base); +unsigned long __hyp_get_vectors(void); +#else +#define __boot_cpu_mode (SVC_MODE) +#endif + +#ifndef ZIMAGE +void hyp_mode_check(void); + +/* Reports the availability of HYP mode */ +static inline bool is_hyp_mode_available(void) +{ + return ((__boot_cpu_mode & MODE_MASK) == HYP_MODE && + !(__boot_cpu_mode & BOOT_CPU_MODE_MISMATCH)); +} + +/* Check if the bootloader has booted CPUs in different modes */ +static inline bool is_hyp_mode_mismatched(void) +{ + return !!(__boot_cpu_mode & BOOT_CPU_MODE_MISMATCH); +} +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* ! VIRT_H */ diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5dfef9d97ed9..5bbec7b8183e 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -81,4 +81,6 @@ head-y := head$(MMUEXT).o obj-$(CONFIG_DEBUG_LL) += debug.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o + extra-y := $(head-y) vmlinux.lds diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index e340fa1db203..417bac1846bd 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -86,35 +86,14 @@ ENDPROC(ret_to_user) */ ENTRY(ret_from_fork) bl schedule_tail + cmp r5, #0 + movne r0, r4 + movne lr, pc + movne pc, r5 get_thread_info tsk - mov why, #1 b ret_slow_syscall ENDPROC(ret_from_fork) -ENTRY(ret_from_kernel_thread) - UNWIND(.fnstart) - UNWIND(.cantunwind) - bl schedule_tail - mov r0, r4 - adr lr, BSYM(1f) @ kernel threads should not exit - mov pc, r5 -1: bl do_exit - nop - UNWIND(.fnend) -ENDPROC(ret_from_kernel_thread) - -/* - * turn a kernel thread into userland process - * use: ret_from_kernel_execve(struct pt_regs *normal) - */ -ENTRY(ret_from_kernel_execve) - mov why, #0 @ not a syscall - str why, [r0, #S_R0] @ ... and we want 0 in ->ARM_r0 as well - get_thread_info tsk @ thread structure - mov sp, r0 @ stack pointer just under pt_regs - b ret_slow_syscall -ENDPROC(ret_from_kernel_execve) - .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 9874d0741191..4eee351f4668 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -83,8 +83,12 @@ ENTRY(stext) THUMB( .thumb ) @ switch to Thumb now. THUMB(1: ) - setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode - @ and irqs disabled +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install +#endif + @ ensure svc mode and all interrupts masked + safe_svcmode_maskall r9 + mrc p15, 0, r9, c0, c0 @ get processor id bl __lookup_processor_type @ r5=procinfo r9=cpuid movs r10, r5 @ invalid processor (r5=0)? @@ -326,7 +330,11 @@ ENTRY(secondary_startup) * the processor type - there is no need to check the machine type * as it has already been validated by the primary processor. */ - setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install +#endif + safe_svcmode_maskall r9 + mrc p15, 0, r9, c0, c0 @ get processor id bl __lookup_processor_type movs r10, r5 @ invalid processor? diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S new file mode 100644 index 000000000000..65b2417aebce --- /dev/null +++ b/arch/arm/kernel/hyp-stub.S @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2012 Linaro Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/virt.h> + +#ifndef ZIMAGE +/* + * For the kernel proper, we need to find out the CPU boot mode long after + * boot, so we need to store it in a writable variable. + * + * This is not in .bss, because we set it sufficiently early that the boot-time + * zeroing of .bss would clobber it. + */ +.data +ENTRY(__boot_cpu_mode) + .long 0 +.text + + /* + * Save the primary CPU boot mode. Requires 3 scratch registers. + */ + .macro store_primary_cpu_mode reg1, reg2, reg3 + mrs \reg1, cpsr + and \reg1, \reg1, #MODE_MASK + adr \reg2, .L__boot_cpu_mode_offset + ldr \reg3, [\reg2] + str \reg1, [\reg2, \reg3] + .endm + + /* + * Compare the current mode with the one saved on the primary CPU. + * If they don't match, record that fact. The Z bit indicates + * if there's a match or not. + * Requires 3 additionnal scratch registers. + */ + .macro compare_cpu_mode_with_primary mode, reg1, reg2, reg3 + adr \reg2, .L__boot_cpu_mode_offset + ldr \reg3, [\reg2] + ldr \reg1, [\reg2, \reg3] + cmp \mode, \reg1 @ matches primary CPU boot mode? + orrne r7, r7, #BOOT_CPU_MODE_MISMATCH + strne r7, [r5, r6] @ record what happened and give up + .endm + +#else /* ZIMAGE */ + + .macro store_primary_cpu_mode reg1:req, reg2:req, reg3:req + .endm + +/* + * The zImage loader only runs on one CPU, so we don't bother with mult-CPU + * consistency checking: + */ + .macro compare_cpu_mode_with_primary mode, reg1, reg2, reg3 + cmp \mode, \mode + .endm + +#endif /* ZIMAGE */ + +/* + * Hypervisor stub installation functions. + * + * These must be called with the MMU and D-cache off. + * They are not ABI compliant and are only intended to be called from the kernel + * entry points in head.S. + */ +@ Call this from the primary CPU +ENTRY(__hyp_stub_install) + store_primary_cpu_mode r4, r5, r6 +ENDPROC(__hyp_stub_install) + + @ fall through... + +@ Secondary CPUs should call here +ENTRY(__hyp_stub_install_secondary) + mrs r4, cpsr + and r4, r4, #MODE_MASK + + /* + * If the secondary has booted with a different mode, give up + * immediately. + */ + compare_cpu_mode_with_primary r4, r5, r6, r7 + bxne lr + + /* + * Once we have given up on one CPU, we do not try to install the + * stub hypervisor on the remaining ones: because the saved boot mode + * is modified, it can't compare equal to the CPSR mode field any + * more. + * + * Otherwise... + */ + + cmp r4, #HYP_MODE + bxne lr @ give up if the CPU is not in HYP mode + +/* + * Configure HSCTLR to set correct exception endianness/instruction set + * state etc. + * Turn off all traps + * Eventually, CPU-specific code might be needed -- assume not for now + * + * This code relies on the "eret" instruction to synchronize the + * various coprocessor accesses. + */ + @ Now install the hypervisor stub: + adr r7, __hyp_stub_vectors + mcr p15, 4, r7, c12, c0, 0 @ set hypervisor vector base (HVBAR) + + @ Disable all traps, so we don't get any nasty surprise + mov r7, #0 + mcr p15, 4, r7, c1, c1, 0 @ HCR + mcr p15, 4, r7, c1, c1, 2 @ HCPTR + mcr p15, 4, r7, c1, c1, 3 @ HSTR + +THUMB( orr r7, #(1 << 30) ) @ HSCTLR.TE +#ifdef CONFIG_CPU_BIG_ENDIAN + orr r7, #(1 << 9) @ HSCTLR.EE +#endif + mcr p15, 4, r7, c1, c0, 0 @ HSCTLR + + mrc p15, 4, r7, c1, c1, 1 @ HDCR + and r7, #0x1f @ Preserve HPMN + mcr p15, 4, r7, c1, c1, 1 @ HDCR + +#if !defined(ZIMAGE) && defined(CONFIG_ARM_ARCH_TIMER) + @ make CNTP_* and CNTPCT accessible from PL1 + mrc p15, 0, r7, c0, c1, 1 @ ID_PFR1 + lsr r7, #16 + and r7, #0xf + cmp r7, #1 + bne 1f + mrc p15, 4, r7, c14, c1, 0 @ CNTHCTL + orr r7, r7, #3 @ PL1PCEN | PL1PCTEN + mcr p15, 4, r7, c14, c1, 0 @ CNTHCTL +1: +#endif + + bic r7, r4, #MODE_MASK + orr r7, r7, #SVC_MODE +THUMB( orr r7, r7, #PSR_T_BIT ) + msr spsr_cxsf, r7 @ This is SPSR_hyp. + + __MSR_ELR_HYP(14) @ msr elr_hyp, lr + __ERET @ return, switching to SVC mode + @ The boot CPU mode is left in r4. +ENDPROC(__hyp_stub_install_secondary) + +__hyp_stub_do_trap: + cmp r0, #-1 + mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR + mcrne p15, 4, r0, c12, c0, 0 @ set HVBAR + __ERET +ENDPROC(__hyp_stub_do_trap) + +/* + * __hyp_set_vectors: Call this after boot to set the initial hypervisor + * vectors as part of hypervisor installation. On an SMP system, this should + * be called on each CPU. + * + * r0 must be the physical address of the new vector table (which must lie in + * the bottom 4GB of physical address space. + * + * r0 must be 32-byte aligned. + * + * Before calling this, you must check that the stub hypervisor is installed + * everywhere, by waiting for any secondary CPUs to be brought up and then + * checking that BOOT_CPU_MODE_HAVE_HYP(__boot_cpu_mode) is true. + * + * If not, there is a pre-existing hypervisor, some CPUs failed to boot, or + * something else went wrong... in such cases, trying to install a new + * hypervisor is unlikely to work as desired. + * + * When you call into your shiny new hypervisor, sp_hyp will contain junk, + * so you will need to set that to something sensible at the new hypervisor's + * initialisation entry point. + */ +ENTRY(__hyp_get_vectors) + mov r0, #-1 +ENDPROC(__hyp_get_vectors) + @ fall through +ENTRY(__hyp_set_vectors) + __HVC(0) + bx lr +ENDPROC(__hyp_set_vectors) + +#ifndef ZIMAGE +.align 2 +.L__boot_cpu_mode_offset: + .long __boot_cpu_mode - . +#endif + +.align 5 +__hyp_stub_vectors: +__hyp_stub_reset: W(b) . +__hyp_stub_und: W(b) . +__hyp_stub_svc: W(b) . +__hyp_stub_pabort: W(b) . +__hyp_stub_dabort: W(b) . +__hyp_stub_trap: W(b) __hyp_stub_do_trap +__hyp_stub_irq: W(b) . +__hyp_stub_fiq: W(b) . +ENDPROC(__hyp_stub_vectors) + diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index f98c17ff1957..90084a6de35a 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -373,7 +373,6 @@ void release_thread(struct task_struct *dead_task) } asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); int copy_thread(unsigned long clone_flags, unsigned long stack_start, @@ -388,13 +387,13 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, *childregs = *regs; childregs->ARM_r0 = 0; childregs->ARM_sp = stack_start; - thread->cpu_context.pc = (unsigned long)ret_from_fork; } else { + memset(childregs, 0, sizeof(struct pt_regs)); thread->cpu_context.r4 = stk_sz; thread->cpu_context.r5 = stack_start; - thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread; childregs->ARM_cpsr = SVC_MODE; } + thread->cpu_context.pc = (unsigned long)ret_from_fork; thread->cpu_context.sp = (unsigned long)childregs; clear_ptrace_hw_breakpoint(p); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index febafa0f552d..da1d1aa20ad9 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -53,6 +53,7 @@ #include <asm/traps.h> #include <asm/unwind.h> #include <asm/memblock.h> +#include <asm/virt.h> #include "atags.h" #include "tcm.h" @@ -703,6 +704,21 @@ static int __init meminfo_cmp(const void *_a, const void *_b) return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } +void __init hyp_mode_check(void) +{ +#ifdef CONFIG_ARM_VIRT_EXT + if (is_hyp_mode_available()) { + pr_info("CPU: All CPU(s) started in HYP mode.\n"); + pr_info("CPU: Virtualization extensions available.\n"); + } else if (is_hyp_mode_mismatched()) { + pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n", + __boot_cpu_mode & MODE_MASK); + pr_warn("CPU: This may indicate a broken bootloader or firmware.\n"); + } else + pr_info("CPU: All CPU(s) started in SVC mode.\n"); +#endif +} + void __init setup_arch(char **cmdline_p) { struct machine_desc *mdesc; @@ -748,6 +764,10 @@ void __init setup_arch(char **cmdline_p) smp_init_cpus(); } #endif + + if (!is_smp()) + hyp_mode_check(); + reserve_crashkernel(); tcm_init(); diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index f27789e4e38a..56f72d257ebd 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -10,7 +10,6 @@ #include <linux/errno.h> #include <linux/signal.h> #include <linux/personality.h> -#include <linux/freezer.h> #include <linux/uaccess.h> #include <linux/tracehook.h> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index d100eacdb798..8e20754dd31d 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -43,6 +43,7 @@ #include <asm/ptrace.h> #include <asm/localtimer.h> #include <asm/smp_plat.h> +#include <asm/virt.h> #include <asm/mach/arch.h> /* @@ -202,8 +203,11 @@ int __cpuinit __cpu_disable(void) /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. + * + * Caches are flushed to the Level of Unification Inner Shareable + * to write-back dirty lines to unified caches shared by all CPUs. */ - flush_cache_all(); + flush_cache_louis(); local_flush_tlb_all(); clear_tasks_mm_cpumask(cpu); @@ -355,6 +359,8 @@ void __init smp_cpus_done(unsigned int max_cpus) num_online_cpus(), bogosum / (500000/HZ), (bogosum / (5000/HZ)) % 100); + + hyp_mode_check(); } void __init smp_prepare_boot_cpu(void) diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 1794cc3b0f18..358bca3a995e 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -17,6 +17,8 @@ extern void cpu_resume_mmu(void); */ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) { + u32 *ctx = ptr; + *save_ptr = virt_to_phys(ptr); /* This must correspond to the LDM in cpu_resume() assembly */ @@ -26,7 +28,20 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) cpu_do_suspend(ptr); - flush_cache_all(); + flush_cache_louis(); + + /* + * flush_cache_louis does not guarantee that + * save_ptr and ptr are cleaned to main memory, + * just up to the Level of Unification Inner Shareable. + * Since the context pointer and context itself + * are to be retrieved with the MMU off that + * data must be cleaned from all cache levels + * to main memory using "area" cache primitives. + */ + __cpuc_flush_dcache_area(ctx, ptrsz); + __cpuc_flush_dcache_area(save_ptr, sizeof(*save_ptr)); + outer_clean_range(*save_ptr, *save_ptr + ptrsz); outer_clean_range(virt_to_phys(save_ptr), virt_to_phys(save_ptr) + sizeof(*save_ptr)); diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 6f50c6722276..b4f0565aff63 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -187,6 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 9ac427a702da..a563189cdfc3 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -511,7 +511,7 @@ static struct resource twi_resources[] = { }; static struct platform_device at91rm9200_twi_device = { - .name = "at91_i2c", + .name = "i2c-at91rm9200", .id = -1, .resource = twi_resources, .num_resources = ARRAY_SIZE(twi_resources), diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 30c7f26a4668..ad29f93f20ca 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -211,6 +211,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk), /* more usart lookup table for DT entries */ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), @@ -219,6 +221,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk), CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk), CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk), + CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk), /* more tc lookup table for DT entries */ CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk), diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index af50ff3281c7..a76b8684f52d 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -421,7 +421,6 @@ static struct resource twi_resources[] = { }; static struct platform_device at91sam9260_twi_device = { - .name = "at91_i2c", .id = -1, .resource = twi_resources, .num_resources = ARRAY_SIZE(twi_resources), @@ -429,6 +428,13 @@ static struct platform_device at91sam9260_twi_device = { void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) { + /* IP version is not the same on 9260 and g20 */ + if (cpu_is_at91sam9g20()) { + at91sam9260_twi_device.name = "i2c-at91sam9g20"; + } else { + at91sam9260_twi_device.name = "i2c-at91sam9260"; + } + /* pins used for TWI interface */ at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */ at91_set_multi_drive(AT91_PIN_PA23, 1); diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index f40762c5fede..8d999eb1a137 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -178,6 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk), CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioB", &pioB_clk), CLKDEV_CON_ID("pioC", &pioC_clk), diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 11e9fa835cde..9752f17efba9 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -317,7 +317,6 @@ static struct resource twi_resources[] = { }; static struct platform_device at91sam9261_twi_device = { - .name = "at91_i2c", .id = -1, .resource = twi_resources, .num_resources = ARRAY_SIZE(twi_resources), @@ -325,12 +324,19 @@ static struct platform_device at91sam9261_twi_device = { void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) { + /* IP version is not the same on 9261 and g10 */ + if (cpu_is_at91sam9g10()) { + at91sam9261_twi_device.name = "i2c-at91sam9g10"; + /* I2C PIO must not be configured as open-drain on this chip */ + } else { + at91sam9261_twi_device.name = "i2c-at91sam9261"; + at91_set_multi_drive(AT91_PIN_PA7, 1); + at91_set_multi_drive(AT91_PIN_PA8, 1); + } + /* pins used for TWI interface */ at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */ - at91_set_multi_drive(AT91_PIN_PA7, 1); - at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */ - at91_set_multi_drive(AT91_PIN_PA8, 1); i2c_register_board_info(0, devices, nr_devices); platform_device_register(&at91sam9261_twi_device); diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 144ef5de51b6..6a01d0360dfb 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), CLKDEV_CON_ID("pioA", &pioA_clk), @@ -210,6 +211,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk), CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk), CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk), + CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 7c0898fe20fa..8dde220b42b6 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -599,7 +599,7 @@ static struct resource twi_resources[] = { }; static struct platform_device at91sam9263_twi_device = { - .name = "at91_i2c", + .name = "i2c-at91sam9260", .id = -1, .resource = twi_resources, .num_resources = ARRAY_SIZE(twi_resources), diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index ef6cedd52e3c..84af1b506d92 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -237,6 +237,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk), @@ -254,6 +256,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk), CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk), CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk), + CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index e4c3b3709204..b1596072dcc2 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -653,7 +653,7 @@ static struct resource twi0_resources[] = { }; static struct platform_device at91sam9g45_twi0_device = { - .name = "at91_i2c", + .name = "i2c-at91sam9g10", .id = 0, .resource = twi0_resources, .num_resources = ARRAY_SIZE(twi0_resources), @@ -673,7 +673,7 @@ static struct resource twi1_resources[] = { }; static struct platform_device at91sam9g45_twi1_device = { - .name = "at91_i2c", + .name = "i2c-at91sam9g10", .id = 1, .resource = twi1_resources, .num_resources = ARRAY_SIZE(twi1_resources), @@ -686,18 +686,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in /* pins used for TWI interface */ if (i2c_id == 0) { at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */ - at91_set_multi_drive(AT91_PIN_PA20, 1); - at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */ - at91_set_multi_drive(AT91_PIN_PA21, 1); platform_device_register(&at91sam9g45_twi0_device); } else { at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */ - at91_set_multi_drive(AT91_PIN_PB10, 1); - at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */ - at91_set_multi_drive(AT91_PIN_PB11, 1); platform_device_register(&at91sam9g45_twi1_device); } diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c index 08494664ab78..732d3d3f4ec5 100644 --- a/arch/arm/mach-at91/at91sam9n12.c +++ b/arch/arm/mach-at91/at91sam9n12.c @@ -169,6 +169,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk), CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk), + CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk), CLKDEV_CON_ID("pioA", &pioAB_clk), CLKDEV_CON_ID("pioB", &pioAB_clk), CLKDEV_CON_ID("pioC", &pioCD_clk), diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 72ce50a50de5..72e908412222 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk), CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioB", &pioB_clk), CLKDEV_CON_ID("pioC", &pioC_clk), diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index deafea0e493d..d6ca0543ce8d 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -346,7 +346,7 @@ static struct resource twi_resources[] = { }; static struct platform_device at91sam9rl_twi_device = { - .name = "at91_i2c", + .name = "i2c-at91sam9g20", .id = -1, .resource = twi_resources, .num_resources = ARRAY_SIZE(twi_resources), diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index 477cf9d06672..e5035380dcbc 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -231,6 +231,9 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk), + CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk), + CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk), CLKDEV_CON_ID("pioA", &pioAB_clk), CLKDEV_CON_ID("pioB", &pioAB_clk), CLKDEV_CON_ID("pioC", &pioCD_clk), diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h deleted file mode 100644 index bb2880f6ba37..000000000000 --- a/arch/arm/mach-at91/include/mach/at91_twi.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/at91_twi.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * Two-wire Interface (TWI) registers. - * Based on AT91RM9200 datasheet revision E. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_TWI_H -#define AT91_TWI_H - -#define AT91_TWI_CR 0x00 /* Control Register */ -#define AT91_TWI_START (1 << 0) /* Send a Start Condition */ -#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */ -#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */ -#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */ -#define AT91_TWI_SVEN (1 << 4) /* Slave Transfer Enable [SAM9260 only] */ -#define AT91_TWI_SVDIS (1 << 5) /* Slave Transfer Disable [SAM9260 only] */ -#define AT91_TWI_SWRST (1 << 7) /* Software Reset */ - -#define AT91_TWI_MMR 0x04 /* Master Mode Register */ -#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */ -#define AT91_TWI_IADRSZ_NO (0 << 8) -#define AT91_TWI_IADRSZ_1 (1 << 8) -#define AT91_TWI_IADRSZ_2 (2 << 8) -#define AT91_TWI_IADRSZ_3 (3 << 8) -#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */ -#define AT91_TWI_DADR (0x7f << 16) /* Device Address */ - -#define AT91_TWI_SMR 0x08 /* Slave Mode Register [SAM9260 only] */ -#define AT91_TWI_SADR (0x7f << 16) /* Slave Address */ - -#define AT91_TWI_IADR 0x0c /* Internal Address Register */ - -#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */ -#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */ -#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */ -#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */ - -#define AT91_TWI_SR 0x20 /* Status Register */ -#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */ -#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */ -#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */ -#define AT91_TWI_SVREAD (1 << 3) /* Slave Read [SAM9260 only] */ -#define AT91_TWI_SVACC (1 << 4) /* Slave Access [SAM9260 only] */ -#define AT91_TWI_GACC (1 << 5) /* General Call Access [SAM9260 only] */ -#define AT91_TWI_OVRE (1 << 6) /* Overrun Error [AT91RM9200 only] */ -#define AT91_TWI_UNRE (1 << 7) /* Underrun Error [AT91RM9200 only] */ -#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */ -#define AT91_TWI_ARBLST (1 << 9) /* Arbitration Lost [SAM9260 only] */ -#define AT91_TWI_SCLWS (1 << 10) /* Clock Wait State [SAM9260 only] */ -#define AT91_TWI_EOSACC (1 << 11) /* End of Slave Address [SAM9260 only] */ - -#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */ -#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */ -#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */ -#define AT91_TWI_RHR 0x30 /* Receive Holding Register */ -#define AT91_TWI_THR 0x34 /* Transmit Holding Register */ - -#endif - diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 2c2d86505a54..5315f05896e9 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -153,7 +153,9 @@ static int at91_pm_verify_clocks(void) } } -#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + if (!IS_ENABLED(CONFIG_AT91_PROGRAMMABLE_CLOCKS)) + return 1; + /* PCK0..PCK3 must be disabled, or configured to use clk32k */ for (i = 0; i < 4; i++) { u32 css; @@ -167,7 +169,6 @@ static int at91_pm_verify_clocks(void) return 0; } } -#endif return 1; } diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index e6f52de1062f..da9881b161e1 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -87,7 +87,7 @@ void __init at91_init_sram(int bank, unsigned long base, unsigned int length) iotable_init(desc, 1); } -static struct map_desc at91_io_desc __initdata = { +static struct map_desc at91_io_desc __initdata __maybe_unused = { .virtual = (unsigned long)AT91_VA_BASE_SYS, .pfn = __phys_to_pfn(AT91_BASE_SYS), .length = SZ_16K, diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index ab99c3c3b752..026b4b277ae5 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -186,6 +186,13 @@ config DA850_UI_RMII NOTE: Please take care while choosing this option, MII PHY will not be functional if RMII mode is selected. +config DA850_UI_SD_VIDEO_PORT + bool "Video Port Interface" + help + Say Y if you want to use Video Port Interface (VPIF) on the + DA850/OMAP-L138 EVM. The Video decoders/encoders are found on the + UI daughter card that is supplied with the EVM. + endchoice config DA850_WL12XX diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 1295e616ceee..32ee3f895967 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -45,6 +45,9 @@ #include <linux/platform_data/mtd-davinci-aemif.h> #include <linux/platform_data/spi-davinci.h> +#include <media/tvp514x.h> +#include <media/adv7343.h> + #define DA850_EVM_PHY_ID "davinci_mdio-0:00" #define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8) #define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15) @@ -452,6 +455,15 @@ static void da850_evm_ui_keys_init(unsigned gpio) } } +#ifdef CONFIG_DA850_UI_SD_VIDEO_PORT +static inline void da850_evm_setup_video_port(int video_sel) +{ + gpio_set_value_cansleep(video_sel, 0); +} +#else +static inline void da850_evm_setup_video_port(int video_sel) { } +#endif + static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *c) { @@ -497,6 +509,8 @@ static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio, da850_evm_setup_emac_rmii(sel_a); + da850_evm_setup_video_port(sel_c); + return 0; exp_setup_keys_fail: @@ -1149,6 +1163,169 @@ static __init int da850_evm_init_cpufreq(void) static __init int da850_evm_init_cpufreq(void) { return 0; } #endif +#if defined(CONFIG_DA850_UI_SD_VIDEO_PORT) + +#define TVP5147_CH0 "tvp514x-0" +#define TVP5147_CH1 "tvp514x-1" + +/* VPIF capture configuration */ +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1, +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +static const struct vpif_input da850_ch0_inputs[] = { + { + .input = { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, + .std = TVP514X_STD_ALL, + }, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .subdev_name = TVP5147_CH0, + }, +}; + +static const struct vpif_input da850_ch1_inputs[] = { + { + .input = { + .index = 0, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, + .std = TVP514X_STD_ALL, + }, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .subdev_name = TVP5147_CH1, + }, +}; + +static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { + { + .name = TVP5147_CH0, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + }, + { + .name = TVP5147_CH1, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5c), + .platform_data = &tvp5146_pdata, + }, + }, +}; + +static struct vpif_capture_config da850_vpif_capture_config = { + .subdev_info = da850_vpif_capture_sdev_info, + .subdev_count = ARRAY_SIZE(da850_vpif_capture_sdev_info), + .chan_config[0] = { + .inputs = da850_ch0_inputs, + .input_count = ARRAY_SIZE(da850_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + .chan_config[1] = { + .inputs = da850_ch1_inputs, + .input_count = ARRAY_SIZE(da850_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + .card_name = "DA850/OMAP-L138 Video Capture", +}; + +/* VPIF display configuration */ +static struct vpif_subdev_info da850_vpif_subdev[] = { + { + .name = "adv7343", + .board_info = { + I2C_BOARD_INFO("adv7343", 0x2a), + }, + }, +}; + +static const struct vpif_output da850_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, +}; + +static struct vpif_display_config da850_vpif_display_config = { + .subdevinfo = da850_vpif_subdev, + .subdev_count = ARRAY_SIZE(da850_vpif_subdev), + .chan_config[0] = { + .outputs = da850_ch0_outputs, + .output_count = ARRAY_SIZE(da850_ch0_outputs), + }, + .card_name = "DA850/OMAP-L138 Video Display", +}; + +static __init void da850_vpif_init(void) +{ + int ret; + + ret = da850_register_vpif(); + if (ret) + pr_warn("da850_evm_init: VPIF setup failed: %d\n", ret); + + ret = davinci_cfg_reg_list(da850_vpif_capture_pins); + if (ret) + pr_warn("da850_evm_init: VPIF capture mux setup failed: %d\n", + ret); + + ret = da850_register_vpif_capture(&da850_vpif_capture_config); + if (ret) + pr_warn("da850_evm_init: VPIF capture setup failed: %d\n", ret); + + ret = davinci_cfg_reg_list(da850_vpif_display_pins); + if (ret) + pr_warn("da850_evm_init: VPIF display mux setup failed: %d\n", + ret); + + ret = da850_register_vpif_display(&da850_vpif_display_config); + if (ret) + pr_warn("da850_evm_init: VPIF display setup failed: %d\n", ret); +} + +#else +static __init void da850_vpif_init(void) {} +#endif + #ifdef CONFIG_DA850_WL12XX static void wl12xx_set_power(int index, bool power_on) @@ -1375,6 +1552,8 @@ static __init void da850_evm_init(void) pr_warning("da850_evm_init: suspend registration failed: %d\n", ret); + da850_vpif_init(); + ret = da8xx_register_spi(1, da850evm_spi_info, ARRAY_SIZE(da850evm_spi_info)); if (ret) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index ca72fc4b8cca..f22572cee49d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -23,6 +23,7 @@ #include <linux/phy.h> #include <linux/clk.h> #include <linux/videodev2.h> +#include <linux/v4l2-dv-timings.h> #include <linux/export.h> #include <media/tvp514x.h> @@ -620,7 +621,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "ntsc", .timings_type = VPBE_ENC_STD, - .timings = {V4L2_STD_525_60}, + .std_id = V4L2_STD_525_60, .interlaced = 1, .xres = 720, .yres = 480, @@ -632,7 +633,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "pal", .timings_type = VPBE_ENC_STD, - .timings = {V4L2_STD_625_50}, + .std_id = V4L2_STD_625_50, .interlaced = 1, .xres = 720, .yres = 576, @@ -647,8 +648,8 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { { .name = "480p59_94", - .timings_type = VPBE_ENC_DV_PRESET, - .timings = {V4L2_DV_480P59_94}, + .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, .interlaced = 0, .xres = 720, .yres = 480, @@ -659,8 +660,8 @@ static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { }, { .name = "576p50", - .timings_type = VPBE_ENC_DV_PRESET, - .timings = {V4L2_DV_576P50}, + .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X576P50, .interlaced = 0, .xres = 720, .yres = 576, @@ -698,7 +699,7 @@ static struct vpbe_output dm644xevm_vpbe_outputs[] = { .index = 1, .name = "Component", .type = V4L2_OUTPUT_TYPE_ANALOG, - .capabilities = V4L2_OUT_CAP_PRESETS, + .capabilities = V4L2_OUT_CAP_DV_TIMINGS, }, .subdev_name = VPBE_VENC_SUBDEV_NAME, .default_mode = "480p59_94", diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 9944367b4931..1dbf85beed1b 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -26,6 +26,7 @@ #include <linux/i2c/pcf857x.h> #include <media/tvp514x.h> +#include <media/adv7343.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> @@ -496,18 +497,49 @@ static struct vpif_subdev_info dm646x_vpif_subdev[] = { }, }; -static const char *output[] = { - "Composite", - "Component", - "S-Video", +static const struct vpif_output dm6467_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPONENT_ID, + }, + { + .output = { + .index = 2, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, }; static struct vpif_display_config dm646x_vpif_display_config = { .set_clock = set_vpif_clock, .subdevinfo = dm646x_vpif_subdev, .subdev_count = ARRAY_SIZE(dm646x_vpif_subdev), - .output = output, - .output_count = ARRAY_SIZE(output), + .chan_config[0] = { + .outputs = dm6467_ch0_outputs, + .output_count = ARRAY_SIZE(dm6467_ch0_outputs), + }, .card_name = "DM646x EVM", }; @@ -601,15 +633,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, - .input = INPUT_CVBS_VI2B, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, { .name = TVP5147_CH1, @@ -617,15 +640,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5c), .platform_data = &tvp5146_pdata, }, - .input = INPUT_SVIDEO_VI2C_VI1C, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, }; @@ -635,9 +649,12 @@ static const struct vpif_input dm6467_ch0_inputs[] = { .index = 0, .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, .subdev_name = TVP5147_CH0, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, }, }; @@ -647,9 +664,12 @@ static const struct vpif_input dm6467_ch1_inputs[] = { .index = 0, .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, .subdev_name = TVP5147_CH1, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, }, }; @@ -661,10 +681,22 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = { .chan_config[0] = { .inputs = dm6467_ch0_inputs, .input_count = ARRAY_SIZE(dm6467_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, .chan_config[1] = { .inputs = dm6467_ch1_inputs, .input_count = ARRAY_SIZE(dm6467_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, }; diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 6676dee7104e..b90c172d5541 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -347,6 +347,13 @@ static struct clk spi1_clk = { .flags = DA850_CLK_ASYNC3, }; +static struct clk vpif_clk = { + .name = "vpif", + .parent = &pll0_sysclk2, + .lpsc = DA850_LPSC1_VPIF, + .gpsc = 1, +}; + static struct clk sata_clk = { .name = "sata", .parent = &pll0_sysclk2, @@ -397,6 +404,7 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "usb20", &usb20_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), + CLK("vpif", NULL, &vpif_clk), CLK("ahci", NULL, &sata_clk), CLK(NULL, NULL, NULL), }; @@ -573,6 +581,46 @@ static const struct mux_config da850_pins[] = { MUX_CFG(DA850, GPIO6_10, 13, 20, 15, 8, false) MUX_CFG(DA850, GPIO6_13, 13, 8, 15, 8, false) MUX_CFG(DA850, RTC_ALARM, 0, 28, 15, 2, false) + /* VPIF Capture */ + MUX_CFG(DA850, VPIF_DIN0, 15, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN1, 15, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN2, 14, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN3, 14, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN4, 14, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN5, 14, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN6, 14, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN7, 14, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN8, 16, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN9, 16, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN10, 15, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN11, 15, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN12, 15, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN13, 15, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN14, 15, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN15, 15, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN0, 14, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN1, 14, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN2, 19, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN3, 19, 16, 15, 1, false) + /* VPIF Display */ + MUX_CFG(DA850, VPIF_DOUT0, 17, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT1, 17, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT2, 16, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT3, 16, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT4, 16, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT5, 16, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT6, 16, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT7, 16, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT8, 18, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT9, 18, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT10, 17, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT11, 17, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT12, 17, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT13, 17, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT14, 17, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT15, 17, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKO2, 19, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKO3, 19, 20, 15, 1, false) #endif }; @@ -595,6 +643,26 @@ const short da850_lcdcntl_pins[] __initconst = { -1 }; +const short da850_vpif_capture_pins[] __initdata = { + DA850_VPIF_DIN0, DA850_VPIF_DIN1, DA850_VPIF_DIN2, DA850_VPIF_DIN3, + DA850_VPIF_DIN4, DA850_VPIF_DIN5, DA850_VPIF_DIN6, DA850_VPIF_DIN7, + DA850_VPIF_DIN8, DA850_VPIF_DIN9, DA850_VPIF_DIN10, DA850_VPIF_DIN11, + DA850_VPIF_DIN12, DA850_VPIF_DIN13, DA850_VPIF_DIN14, DA850_VPIF_DIN15, + DA850_VPIF_CLKIN0, DA850_VPIF_CLKIN1, DA850_VPIF_CLKIN2, + DA850_VPIF_CLKIN3, + -1 +}; + +const short da850_vpif_display_pins[] __initdata = { + DA850_VPIF_DOUT0, DA850_VPIF_DOUT1, DA850_VPIF_DOUT2, DA850_VPIF_DOUT3, + DA850_VPIF_DOUT4, DA850_VPIF_DOUT5, DA850_VPIF_DOUT6, DA850_VPIF_DOUT7, + DA850_VPIF_DOUT8, DA850_VPIF_DOUT9, DA850_VPIF_DOUT10, + DA850_VPIF_DOUT11, DA850_VPIF_DOUT12, DA850_VPIF_DOUT13, + DA850_VPIF_DOUT14, DA850_VPIF_DOUT15, DA850_VPIF_CLKO2, + DA850_VPIF_CLKO3, + -1 +}; + /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, @@ -939,7 +1007,7 @@ static struct platform_device da850_cpufreq_device = { unsigned int da850_max_speed = 300000; -int __init da850_register_cpufreq(char *async_clk) +int da850_register_cpufreq(char *async_clk) { int i; @@ -1064,6 +1132,90 @@ no_ddrpll_mem: return ret; } +/* VPIF resource, platform data */ +static u64 da850_vpif_dma_mask = DMA_BIT_MASK(32); + +static struct resource da850_vpif_resource[] = { + { + .start = DA8XX_VPIF_BASE, + .end = DA8XX_VPIF_BASE + 0xfff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device da850_vpif_dev = { + .name = "vpif", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_resource, + .num_resources = ARRAY_SIZE(da850_vpif_resource), +}; + +static struct resource da850_vpif_display_resource[] = { + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da850_vpif_display_dev = { + .name = "vpif_display", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_display_resource, + .num_resources = ARRAY_SIZE(da850_vpif_display_resource), +}; + +static struct resource da850_vpif_capture_resource[] = { + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da850_vpif_capture_dev = { + .name = "vpif_capture", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_capture_resource, + .num_resources = ARRAY_SIZE(da850_vpif_capture_resource), +}; + +int __init da850_register_vpif(void) +{ + return platform_device_register(&da850_vpif_dev); +} + +int __init da850_register_vpif_display(struct vpif_display_config + *display_config) +{ + da850_vpif_display_dev.dev.platform_data = display_config; + return platform_device_register(&da850_vpif_display_dev); +} + +int __init da850_register_vpif_capture(struct vpif_capture_config + *capture_config) +{ + da850_vpif_capture_dev.dev.platform_data = capture_config; + return platform_device_register(&da850_vpif_capture_dev); +} + static struct davinci_soc_info davinci_soc_info_da850 = { .io_desc = da850_io_desc, .io_desc_num = ARRAY_SIZE(da850_io_desc), diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 0755d466221a..cd0c8b1e1ecf 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -701,7 +701,7 @@ static struct resource dm644x_venc_resources[] = { #define DM644X_VPSS_DACCLKEN BIT(4) static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, - unsigned int mode) + unsigned int pclock) { int ret = 0; u32 v = DM644X_VPSS_VENCLKEN; @@ -711,27 +711,18 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); break; - case VPBE_ENC_DV_PRESET: - switch (mode) { - case V4L2_DV_480P59_94: - case V4L2_DV_576P50: + case VPBE_ENC_CUSTOM_TIMINGS: + if (pclock <= 27000000) { v |= DM644X_VPSS_MUXSEL_PLL2_MODE | DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); - break; - case V4L2_DV_720P60: - case V4L2_DV_1080I60: - case V4L2_DV_1080P30: + } else { /* * For HD, use external clock source since * HD requires higher clock rate */ v |= DM644X_VPSS_MUXSEL_VPBECLK_MODE; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); - break; - default: - ret = -EINVAL; - break; } break; default: diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index c9ee723c56f3..aaccdc4528fc 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -17,6 +17,7 @@ #include <linux/davinci_emac.h> #include <linux/spi/spi.h> #include <linux/platform_data/davinci_asp.h> +#include <linux/videodev2.h> #include <mach/serial.h> #include <mach/edma.h> @@ -26,6 +27,8 @@ #include <linux/platform_data/usb-davinci.h> #include <linux/platform_data/spi-davinci.h> +#include <media/davinci/vpif_types.h> + extern void __iomem *da8xx_syscfg0_base; extern void __iomem *da8xx_syscfg1_base; @@ -63,6 +66,7 @@ extern unsigned int da850_max_speed; #define DA8XX_PLL0_BASE 0x01c11000 #define DA8XX_TIMER64P0_BASE 0x01c20000 #define DA8XX_TIMER64P1_BASE 0x01c21000 +#define DA8XX_VPIF_BASE 0x01e17000 #define DA8XX_GPIO_BASE 0x01e26000 #define DA8XX_PSC1_BASE 0x01e27000 #define DA8XX_AEMIF_CS2_BASE 0x60000000 @@ -92,6 +96,11 @@ int da8xx_register_cpuidle(void); void __iomem * __init da8xx_get_mem_ctlr(void); int da850_register_pm(struct platform_device *pdev); int __init da850_register_sata(unsigned long refclkpn); +int __init da850_register_vpif(void); +int __init da850_register_vpif_display + (struct vpif_display_config *display_config); +int __init da850_register_vpif_capture + (struct vpif_capture_config *capture_config); void da8xx_restart(char mode, const char *cmd); extern struct platform_device da8xx_serial_device; @@ -126,6 +135,8 @@ extern const short da830_ecap1_pins[]; extern const short da830_ecap2_pins[]; extern const short da830_eqep0_pins[]; extern const short da830_eqep1_pins[]; +extern const short da850_vpif_capture_pins[]; +extern const short da850_vpif_display_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index a7e92fca32e6..9e95b8a1edb6 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -928,6 +928,48 @@ enum davinci_da850_index { DA850_GPIO6_10, DA850_GPIO6_13, DA850_RTC_ALARM, + + /* VPIF Capture */ + DA850_VPIF_DIN0, + DA850_VPIF_DIN1, + DA850_VPIF_DIN2, + DA850_VPIF_DIN3, + DA850_VPIF_DIN4, + DA850_VPIF_DIN5, + DA850_VPIF_DIN6, + DA850_VPIF_DIN7, + DA850_VPIF_DIN8, + DA850_VPIF_DIN9, + DA850_VPIF_DIN10, + DA850_VPIF_DIN11, + DA850_VPIF_DIN12, + DA850_VPIF_DIN13, + DA850_VPIF_DIN14, + DA850_VPIF_DIN15, + DA850_VPIF_CLKIN0, + DA850_VPIF_CLKIN1, + DA850_VPIF_CLKIN2, + DA850_VPIF_CLKIN3, + + /* VPIF Display */ + DA850_VPIF_DOUT0, + DA850_VPIF_DOUT1, + DA850_VPIF_DOUT2, + DA850_VPIF_DOUT3, + DA850_VPIF_DOUT4, + DA850_VPIF_DOUT5, + DA850_VPIF_DOUT6, + DA850_VPIF_DOUT7, + DA850_VPIF_DOUT8, + DA850_VPIF_DOUT9, + DA850_VPIF_DOUT10, + DA850_VPIF_DOUT11, + DA850_VPIF_DOUT12, + DA850_VPIF_DOUT13, + DA850_VPIF_DOUT14, + DA850_VPIF_DOUT15, + DA850_VPIF_CLKO2, + DA850_VPIF_CLKO3, }; enum davinci_tnetv107x_index { diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 405318e35bf6..40a0027838e8 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -166,6 +166,7 @@ #define DA830_LPSC1_McASP1 8 #define DA850_LPSC1_SATA 8 #define DA830_LPSC1_McASP2 9 +#define DA850_LPSC1_VPIF 9 #define DA8XX_LPSC1_SPI1 10 #define DA8XX_LPSC1_I2C 11 #define DA8XX_LPSC1_UART1 12 diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 480cd78f1920..c05d7aa84031 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -29,6 +29,7 @@ #include <drm/exynos_drm.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <media/m5mols.h> #include <media/s5k6aa.h> #include <media/s5p_fimc.h> @@ -39,7 +40,6 @@ #include <asm/mach-types.h> #include <plat/adc.h> -#include <plat/regs-fb-v4.h> #include <plat/regs-serial.h> #include <plat/cpu.h> #include <plat/devs.h> @@ -378,10 +378,10 @@ static struct regulator_consumer_supply __initdata max8997_ldo1_[] = { }; static struct regulator_consumer_supply __initdata max8997_ldo3_[] = { REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"), /* USB */ - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata max8997_ldo4_[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata max8997_ldo5_[] = { REGULATOR_SUPPLY("vhsic", "modemctl"), /* MODEM */ @@ -1180,9 +1180,7 @@ static struct platform_device cam_8m_12v_fixed_rdev = { static struct s5p_platform_mipi_csis mipi_csis_platdata = { .clk_rate = 166000000UL, .lanes = 2, - .alignment = 32, .hs_settle = 12, - .phy_enable = s5p_csis_phy_enable, }; #define GPIO_CAM_MEGA_RST EXYNOS4_GPY3(7) /* ISP_RESET */ @@ -1226,7 +1224,6 @@ static struct s5p_fimc_isp_info nuri_camera_sensors[] = { .bus_type = FIMC_MIPI_CSI2, .board_info = &m5mols_board_info, .clk_frequency = 24000000UL, - .csi_data_align = 32, }, }; diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 67b50bb89c0f..9adf491674ea 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -30,9 +30,9 @@ #include <asm/mach-types.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <plat/regs-serial.h> -#include <plat/regs-fb-v4.h> #include <plat/cpu.h> #include <plat/devs.h> #include <plat/sdhci.h> @@ -97,12 +97,12 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }; static struct regulator_consumer_supply __initdata ldo3_consumer[] = { - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), /* HDMI */ REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"), /* HDMI */ }; static struct regulator_consumer_supply __initdata ldo6_consumer[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata ldo7_consumer[] = { REGULATOR_SUPPLY("avdd", "alc5625"), /* Realtek ALC5625 */ diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c index 7a265d1a82d3..730f1ac65928 100644 --- a/arch/arm/mach-exynos/mach-smdk4x12.c +++ b/arch/arm/mach-exynos/mach-smdk4x12.c @@ -27,6 +27,7 @@ #include <asm/hardware/gic.h> #include <asm/mach-types.h> +#include <video/samsung_fimd.h> #include <plat/backlight.h> #include <plat/clock.h> #include <plat/cpu.h> @@ -36,7 +37,6 @@ #include <linux/platform_data/i2c-s3c2410.h> #include <plat/keypad.h> #include <plat/mfc.h> -#include <plat/regs-fb.h> #include <plat/regs-serial.h> #include <plat/sdhci.h> diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index c15d2238ceb0..ee4fb1a9cb72 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -27,9 +27,9 @@ #include <asm/mach-types.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <plat/regs-serial.h> #include <plat/regs-srom.h> -#include <plat/regs-fb-v4.h> #include <plat/cpu.h> #include <plat/devs.h> #include <plat/fb.h> diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 98d3aced2289..ebc9dd339a38 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -30,6 +30,7 @@ #include <asm/hardware/gic.h> #include <asm/mach-types.h> +#include <video/samsung_fimd.h> #include <plat/regs-serial.h> #include <plat/clock.h> #include <plat/cpu.h> @@ -39,7 +40,6 @@ #include <plat/fb.h> #include <plat/mfc.h> #include <plat/sdhci.h> -#include <plat/regs-fb-v4.h> #include <plat/fimc-core.h> #include <plat/s5p-time.h> #include <plat/camport.h> @@ -209,7 +209,7 @@ static struct regulator_consumer_supply lp3974_ldo3_consumer[] = { REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"), REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"), - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), }; static struct regulator_init_data lp3974_ldo3_data = { @@ -273,7 +273,7 @@ static struct regulator_init_data lp3974_ldo6_data = { }; static struct regulator_consumer_supply lp3974_ldo7_consumer[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), }; static struct regulator_init_data lp3974_ldo7_data = { @@ -942,9 +942,7 @@ static struct platform_device cam_s_if_fixed_reg_dev = { static struct s5p_platform_mipi_csis mipi_csis_platdata = { .clk_rate = 166000000UL, .lanes = 2, - .alignment = 32, .hs_settle = 12, - .phy_enable = s5p_csis_phy_enable, }; #define GPIO_CAM_LEVEL_EN(n) EXYNOS4_GPE4(n + 3) @@ -1008,7 +1006,6 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = { .board_info = &m5mols_board_info, .i2c_bus_num = 0, .clk_frequency = 24000000UL, - .csi_data_align = 32, }, }; diff --git a/arch/arm/mach-exynos/setup-fimd0.c b/arch/arm/mach-exynos/setup-fimd0.c index 07a6dbeecdd0..5665bb4e980b 100644 --- a/arch/arm/mach-exynos/setup-fimd0.c +++ b/arch/arm/mach-exynos/setup-fimd0.c @@ -13,8 +13,8 @@ #include <linux/fb.h> #include <linux/gpio.h> +#include <video/samsung_fimd.h> #include <plat/gpio-cfg.h> -#include <plat/regs-fb-v4.h> #include <mach/map.h> diff --git a/arch/arm/mach-footbridge/include/mach/irqs.h b/arch/arm/mach-footbridge/include/mach/irqs.h index 400551e43e4e..61c714c4920e 100644 --- a/arch/arm/mach-footbridge/include/mach/irqs.h +++ b/arch/arm/mach-footbridge/include/mach/irqs.h @@ -89,8 +89,6 @@ #define IRQ_NETWINDER_VGA _ISA_IRQ(11) #define IRQ_NETWINDER_SOUND _ISA_IRQ(12) -#undef RTC_IRQ -#define RTC_IRQ IRQ_ISA_RTC_ALARM #define I8042_KBD_IRQ IRQ_ISA_KEYBOARD #define I8042_AUX_IRQ (machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE) #define IRQ_FLOPPYDISK IRQ_ISA_FLOPPY diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h index 1a78692e32a4..202e6a57f100 100644 --- a/arch/arm/mach-integrator/include/mach/cm.h +++ b/arch/arm/mach-integrator/include/mach/cm.h @@ -3,7 +3,7 @@ */ void cm_control(u32, u32); -#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL) +#define CM_CTRL __io_address(INTEGRATOR_HDR_CTRL) #define CM_CTRL_LED (1 << 0) #define CM_CTRL_nMBDET (1 << 1) diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h index 4c0347526851..efeac5d0bc9e 100644 --- a/arch/arm/mach-integrator/include/mach/platform.h +++ b/arch/arm/mach-integrator/include/mach/platform.h @@ -324,9 +324,9 @@ */ #define PHYS_PCI_V3_BASE 0x62000000 -#define PCI_MEMORY_VADDR 0xe8000000 -#define PCI_CONFIG_VADDR 0xec000000 -#define PCI_V3_VADDR 0xed000000 +#define PCI_MEMORY_VADDR IOMEM(0xe8000000) +#define PCI_CONFIG_VADDR IOMEM(0xec000000) +#define PCI_V3_VADDR IOMEM(0xed000000) /* ------------------------------------------------------------------------ * Integrator Interrupt Controllers diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index d5b5435a09ae..e6617c134faf 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -157,7 +157,7 @@ static struct map_desc ap_io_desc[] __initdata = { static void __init ap_map_io(void) { iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc)); - vga_base = PCI_MEMORY_VADDR; + vga_base = (unsigned long)PCI_MEMORY_VADDR; pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE)); } diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 6870a1fbcd78..5b08e8e4cc83 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -261,6 +261,8 @@ static void __init intcp_init_early(void) #endif } +#ifdef CONFIG_OF + static void __init intcp_timer_init_of(void) { struct device_node *node; @@ -297,8 +299,6 @@ static struct sys_timer cp_of_timer = { .init = intcp_timer_init_of, }; -#ifdef CONFIG_OF - static const struct of_device_id fpga_irq_of_match[] __initconst = { { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, { /* Sentinel */ } diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c index 060cddde2fd4..e94744111634 100644 --- a/arch/arm/mach-iop13xx/iq81340sc.c +++ b/arch/arm/mach-iop13xx/iq81340sc.c @@ -30,7 +30,7 @@ extern int init_atu; static int __init -iq81340sc_atux_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +iq81340sc_atux_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin) { WARN_ON(idsel < 1 || idsel > 2); diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c index 9082b84aeebb..2f28018c4447 100644 --- a/arch/arm/mach-iop13xx/pci.c +++ b/arch/arm/mach-iop13xx/pci.c @@ -504,7 +504,7 @@ iop13xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) /* Scan an IOP13XX PCI bus. nr selects which ATU we use. */ -struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) +struct pci_bus * __devinit iop13xx_scan_bus(int nr, struct pci_sys_data *sys) { int which_atu; struct pci_bus *bus = NULL; diff --git a/arch/arm/mach-ks8695/include/mach/memory.h b/arch/arm/mach-ks8695/include/mach/memory.h index f7e1b9bce345..95e731a7ed6a 100644 --- a/arch/arm/mach-ks8695/include/mach/memory.h +++ b/arch/arm/mach-ks8695/include/mach/memory.h @@ -34,7 +34,8 @@ extern struct bus_type platform_bus_type; #define __arch_dma_to_virt(dev, x) ({ (void *) (is_lbus_device(dev) ? \ __phys_to_virt(x) : __bus_to_virt(x)); }) #define __arch_virt_to_dma(dev, x) ({ is_lbus_device(dev) ? \ - (dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); }) + (dma_addr_t)__virt_to_phys((unsigned long)x) \ + : (dma_addr_t)__virt_to_bus(x); }) #define __arch_pfn_to_dma(dev, pfn) \ ({ dma_addr_t __dma = __pfn_to_phys(pfn); \ if (!is_lbus_device(dev)) \ diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c index 343c435b4176..26e9876b50e9 100644 --- a/arch/arm/mach-mv78xx0/addr-map.c +++ b/arch/arm/mach-mv78xx0/addr-map.c @@ -54,7 +54,7 @@ static void __init __iomem *win_cfg_base(const struct orion_addr_map_cfg *cfg, i /* * Description of the windows needed by the platform code */ -static struct __initdata orion_addr_map_cfg addr_map_cfg = { +static struct orion_addr_map_cfg addr_map_cfg __initdata = { .num_wins = 14, .remappable_wins = 8, .win_cfg_base = win_cfg_base, diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index 131cd4883f3d..d0cb4857b4b3 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -336,7 +336,7 @@ void __init mv78xx0_init_early(void) orion_time_set_base(TIMER_VIRT_BASE); } -static void mv78xx0_timer_init(void) +static void __init_refok mv78xx0_timer_init(void) { orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR, IRQ_MV78XX0_TIMER_1, get_tclk()); diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index 726c02c9c0cd..d3fec92c54cb 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -231,7 +231,7 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, omap_mmc_add("mmci-omap", i, base, size, irq, rx_req, tx_req, mmc_data[i]); - }; + } } #endif diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index a88809a59ea9..3669c120c7e8 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -607,29 +607,6 @@ static void __init omap_sfh7741prox_init(void) __func__, OMAP4_SFH7741_ENABLE_GPIO, error); } -static struct gpio sdp4430_hdmi_gpios[] = { - { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, - { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, - { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, -}; - -static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) -{ - int status; - - status = gpio_request_array(sdp4430_hdmi_gpios, - ARRAY_SIZE(sdp4430_hdmi_gpios)); - if (status) - pr_err("%s: Cannot request HDMI GPIOs\n", __func__); - - return status; -} - -static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) -{ - gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); -} - static struct nokia_dsi_panel_data dsi1_panel = { .name = "taal", .reset_gpio = 102, @@ -650,29 +627,6 @@ static struct omap_dss_device sdp4430_lcd_device = { .phy.dsi = { .module = 0, }, - - .clocks = { - .dispc = { - .channel = { - /* Logic Clock = 172.8 MHz */ - .lck_div = 1, - /* Pixel Clock = 34.56 MHz */ - .pck_div = 5, - .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, - }, - .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, - }, - - .dsi = { - .regn = 16, /* Fint = 2.4 MHz */ - .regm = 180, /* DDR Clock = 216 MHz */ - .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ - .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ - - .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ - .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, - }, - }, .channel = OMAP_DSS_CHANNEL_LCD, }; @@ -697,33 +651,12 @@ static struct omap_dss_device sdp4430_lcd2_device = { .module = 1, }, - - .clocks = { - .dispc = { - .channel = { - /* Logic Clock = 172.8 MHz */ - .lck_div = 1, - /* Pixel Clock = 34.56 MHz */ - .pck_div = 5, - .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC, - }, - .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, - }, - - .dsi = { - .regn = 16, /* Fint = 2.4 MHz */ - .regm = 180, /* DDR Clock = 216 MHz */ - .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ - .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ - - .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ - .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, - }, - }, .channel = OMAP_DSS_CHANNEL_LCD2, }; static struct omap_dss_hdmi_data sdp4430_hdmi_data = { + .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD, + .ls_oe_gpio = HDMI_GPIO_LS_OE, .hpd_gpio = HDMI_GPIO_HPD, }; @@ -731,8 +664,6 @@ static struct omap_dss_device sdp4430_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", .type = OMAP_DISPLAY_TYPE_HDMI, - .platform_enable = sdp4430_panel_enable_hdmi, - .platform_disable = sdp4430_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, .data = &sdp4430_hdmi_data, }; @@ -830,6 +761,32 @@ static struct omap_board_mux board_mux[] __initdata = { /* NIRQ2 for twl6040 */ OMAP4_MUX(SYS_NIRQ2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE), + /* GPIO_127 for twl6040 */ + OMAP4_MUX(HDQ_SIO, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT), + /* McPDM */ + OMAP4_MUX(ABE_PDM_UL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_PDM_DL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_PDM_FRAME, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(ABE_PDM_LB_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_CLKS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + /* DMIC */ + OMAP4_MUX(ABE_DMIC_CLK1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP4_MUX(ABE_DMIC_DIN1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP4_MUX(ABE_DMIC_DIN2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP4_MUX(ABE_DMIC_DIN3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + /* McBSP1 */ + OMAP4_MUX(ABE_MCBSP1_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP4_MUX(ABE_MCBSP1_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_MCBSP1_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT | + OMAP_PULL_ENA), + OMAP4_MUX(ABE_MCBSP1_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + /* McBSP2 */ + OMAP4_MUX(ABE_MCBSP2_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP4_MUX(ABE_MCBSP2_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_MCBSP2_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT | + OMAP_PULL_ENA), + OMAP4_MUX(ABE_MCBSP2_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + { .reg_offset = OMAP_MUX_TERMINATOR }, }; diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index 0cabe61cd507..e642acf9cad0 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -218,7 +218,7 @@ void __init board_flash_init(struct flash_partitions partition_info[], if (onenandcs > GPMC_CS_NUM) onenandcs = cs; break; - }; + } cs++; } diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index a08bebc94ec5..388c431c745a 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -461,7 +461,7 @@ static void __init beagle_opp_init(void) mpu_dev = omap_device_get_by_hwmod_name("mpu"); iva_dev = omap_device_get_by_hwmod_name("iva"); - if (!mpu_dev || !iva_dev) { + if (IS_ERR(mpu_dev) || IS_ERR(iva_dev)) { pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n", __func__, mpu_dev, iva_dev); return; diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index a3959de85e05..b9b776b6c954 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -88,11 +88,10 @@ enum { static u8 omap3_evm_version; -u8 get_omap3_evm_rev(void) +static u8 get_omap3_evm_rev(void) { return omap3_evm_version; } -EXPORT_SYMBOL(get_omap3_evm_rev); static void __init omap3_evm_get_revision(void) { diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index c7f3d026e6d4..731235eb319e 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -48,11 +48,6 @@ #include <video/omap-panel-tfp410.h> #include <linux/platform_data/spi-omap2-mcspi.h> -#include <linux/input/matrix_keypad.h> -#include <linux/spi/spi.h> -#include <linux/interrupt.h> -#include <linux/smsc911x.h> -#include <linux/i2c/at24.h> #include "sdram-micron-mt46h32m32lf-6.h" #include "mux.h" diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 2b012f9d6925..bfcd397e233c 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -247,8 +247,7 @@ static struct platform_device omap_vwlan_device = { }; static struct wl12xx_platform_data omap_panda_wlan_data __initdata = { - /* PANDA ref clock is 38.4 MHz */ - .board_ref_clock = 2, + .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */ }; static struct twl6040_codec_data twl6040_codec = { @@ -388,6 +387,21 @@ static struct omap_board_mux board_mux[] __initdata = { /* NIRQ2 for twl6040 */ OMAP4_MUX(SYS_NIRQ2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE), + /* GPIO_127 for twl6040 */ + OMAP4_MUX(HDQ_SIO, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT), + /* McPDM */ + OMAP4_MUX(ABE_PDM_UL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_PDM_DL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_PDM_FRAME, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(ABE_PDM_LB_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_CLKS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + /* McBSP1 */ + OMAP4_MUX(ABE_MCBSP1_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP4_MUX(ABE_MCBSP1_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP4_MUX(ABE_MCBSP1_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT | + OMAP_PULL_ENA), + OMAP4_MUX(ABE_MCBSP1_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + { .reg_offset = OMAP_MUX_TERMINATOR }, }; @@ -414,30 +428,9 @@ static struct omap_dss_device omap4_panda_dvi_device = { .channel = OMAP_DSS_CHANNEL_LCD2, }; -static struct gpio panda_hdmi_gpios[] = { - { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, - { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, - { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, -}; - -static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) -{ - int status; - - status = gpio_request_array(panda_hdmi_gpios, - ARRAY_SIZE(panda_hdmi_gpios)); - if (status) - pr_err("Cannot request HDMI GPIOs\n"); - - return status; -} - -static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev) -{ - gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios)); -} - static struct omap_dss_hdmi_data omap4_panda_hdmi_data = { + .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD, + .ls_oe_gpio = HDMI_GPIO_LS_OE, .hpd_gpio = HDMI_GPIO_HPD, }; @@ -445,8 +438,6 @@ static struct omap_dss_device omap4_panda_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", .type = OMAP_DISPLAY_TYPE_HDMI, - .platform_enable = omap4_panda_panel_enable_hdmi, - .platform_disable = omap4_panda_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, .data = &omap4_panda_hdmi_data, }; diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index ed85fb898c7f..020e03c95bfe 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -748,7 +748,7 @@ static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module = .subdev_board_info = &rx51_si4713_board_info, }; -static struct platform_device rx51_si4713_dev = { +static struct platform_device rx51_si4713_dev __initdata_or_module = { .name = "radio-si4713", .id = -1, .dev = { diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 67f8540c8e07..c166fe1fdff9 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -195,8 +195,7 @@ static struct platform_device omap_vwlan_device = { }; static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = { - /* ZOOM ref clock is 26 MHz */ - .board_ref_clock = 1, + .board_ref_clock = WL12XX_REFCLOCK_26, /* 26 MHz */ }; static struct omap2_hsmmc_info mmc[] = { diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c index eaed3900a83c..3ff22114d702 100644 --- a/arch/arm/mach-omap2/clkt_clksel.c +++ b/arch/arm/mach-omap2/clkt_clksel.c @@ -382,7 +382,7 @@ void omap2_init_clksel_parent(struct clk *clk) __clk_get_name(parent) : "NULL")); clk_reparent(clk, clks->parent); - }; + } found = 1; } } diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c index b87b88c2638b..114ab4b8e0e3 100644 --- a/arch/arm/mach-omap2/clock33xx_data.c +++ b/arch/arm/mach-omap2/clock33xx_data.c @@ -1035,6 +1035,8 @@ static struct omap_clk am33xx_clks[] = { CLK(NULL, "pruss_ocp_gclk", &pruss_ocp_gclk, CK_AM33XX), CLK("davinci-mcasp.0", NULL, &mcasp0_fck, CK_AM33XX), CLK("davinci-mcasp.1", NULL, &mcasp1_fck, CK_AM33XX), + CLK(NULL, "mcasp0_fck", &mcasp0_fck, CK_AM33XX), + CLK(NULL, "mcasp1_fck", &mcasp1_fck, CK_AM33XX), CLK("NULL", "mmc2_fck", &mmc2_fck, CK_AM33XX), CLK(NULL, "mmu_fck", &mmu_fck, CK_AM33XX), CLK(NULL, "smartreflex0_fck", &smartreflex0_fck, CK_AM33XX), diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c index 9a7792aec673..70294f54e35a 100644 --- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c @@ -183,17 +183,6 @@ static int omap2_clkdm_clk_enable(struct clockdomain *clkdm) if (!clkdm->clktrctrl_mask) return 0; - /* - * The CLKDM_MISSING_IDLE_REPORTING flag documentation has - * more details on the unpleasant problem this is working - * around - */ - if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING && - !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { - _enable_hwsup(clkdm); - return 0; - } - hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -217,17 +206,6 @@ static int omap2_clkdm_clk_disable(struct clockdomain *clkdm) if (!clkdm->clktrctrl_mask) return 0; - /* - * The CLKDM_MISSING_IDLE_REPORTING flag documentation has - * more details on the unpleasant problem this is working - * around - */ - if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) && - (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { - omap3_clkdm_wakeup(clkdm); - return 0; - } - hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -269,6 +247,17 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) if (!clkdm->clktrctrl_mask) return 0; + /* + * The CLKDM_MISSING_IDLE_REPORTING flag documentation has + * more details on the unpleasant problem this is working + * around + */ + if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) && + (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { + omap3_clkdm_wakeup(clkdm); + return 0; + } + hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -292,6 +281,17 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) if (!clkdm->clktrctrl_mask) return 0; + /* + * The CLKDM_MISSING_IDLE_REPORTING flag documentation has + * more details on the unpleasant problem this is working + * around + */ + if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING && + !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { + _enable_hwsup(clkdm); + return 0; + } + hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 7012068ccbf6..1011995f150a 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -95,7 +95,6 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initconst = { { "dss_core", "omapdss_dss", -1 }, { "dss_dispc", "omapdss_dispc", -1 }, { "dss_rfbi", "omapdss_rfbi", -1 }, - { "dss_venc", "omapdss_venc", -1 }, { "dss_dsi1", "omapdss_dsi", 0 }, { "dss_dsi2", "omapdss_dsi", 1 }, { "dss_hdmi", "omapdss_hdmi", -1 }, @@ -221,7 +220,7 @@ static struct platform_device *create_dss_pdev(const char *pdev_name, ohs[0] = oh; od = omap_device_alloc(pdev, ohs, 1, NULL, 0); - if (!od) { + if (IS_ERR(od)) { pr_err("Could not alloc omap_device for %s\n", pdev_name); r = -ENOMEM; goto err; diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8ab1e1bde5e9..5ac5cf30406a 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -838,7 +838,7 @@ static int gpmc_setup_irq(void) return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL); } -static __exit int gpmc_free_irq(void) +static __devexit int gpmc_free_irq(void) { int i; @@ -944,7 +944,7 @@ static __devinit int gpmc_probe(struct platform_device *pdev) return 0; } -static __exit int gpmc_remove(struct platform_device *pdev) +static __devexit int gpmc_remove(struct platform_device *pdev) { gpmc_free_irq(); gpmc_mem_exit(); diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 03ebf47cfa9a..4d3a6324155f 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -523,7 +523,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); od = omap_device_alloc(pdev, ohs, 1, NULL, 0); - if (!od) { + if (IS_ERR(od)) { pr_err("Could not allocate od for %s\n", name); goto put_pdev; } diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 9fe6829f4c16..701e17cba468 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -486,7 +486,7 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) default: /* Nothing to be done */ break; - }; + } if (val >= 0) { omap_mux_write(pad->partition, val, diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c index a004cb9acf52..e089e4d1ae38 100644 --- a/arch/arm/mach-omap2/omap-secure.c +++ b/arch/arm/mach-omap2/omap-secure.c @@ -61,8 +61,8 @@ int __init omap_secure_ram_reserve_memblock(void) { u32 size = OMAP_SECURE_RAM_STORAGE; - size = ALIGN(size, SZ_1M); - omap_secure_memblock_base = arm_memblock_steal(size, SZ_1M); + size = ALIGN(size, SECTION_SIZE); + omap_secure_memblock_base = arm_memblock_steal(size, SECTION_SIZE); return 0; } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 299ca2821ad1..b969ab1d258b 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1698,6 +1698,29 @@ static bool _are_all_hardreset_lines_asserted(struct omap_hwmod *oh) } /** + * _are_any_hardreset_lines_asserted - return true if any part of @oh is + * hard-reset + * @oh: struct omap_hwmod * + * + * If any hardreset lines associated with @oh are asserted, then + * return true. Otherwise, if no hardreset lines associated with @oh + * are asserted, or if @oh has no hardreset lines, then return false. + * This function is used to avoid executing some parts of the IP block + * enable/disable sequence if any hardreset line is set. + */ +static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh) +{ + int rst_cnt = 0; + int i; + + for (i = 0; i < oh->rst_lines_cnt && rst_cnt == 0; i++) + if (_read_hardreset(oh, oh->rst_lines[i].name) > 0) + rst_cnt++; + + return (rst_cnt) ? true : false; +} + +/** * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4 * @oh: struct omap_hwmod * * @@ -1715,7 +1738,7 @@ static int _omap4_disable_module(struct omap_hwmod *oh) * Since integration code might still be doing something, only * disable if all lines are under hardreset. */ - if (!_are_all_hardreset_lines_asserted(oh)) + if (_are_any_hardreset_lines_asserted(oh)) return 0; pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); @@ -1749,12 +1772,12 @@ static int _am33xx_disable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); + if (_are_any_hardreset_lines_asserted(oh)) + return 0; + am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs); - if (_are_all_hardreset_lines_asserted(oh)) - return 0; - v = _am33xx_wait_target_disable(oh); if (v) pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index 35dcdb66a4e0..bd9220ed5ab9 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -219,7 +219,7 @@ struct omap_hwmod omap2xxx_l4_wkup_hwmod = { /* MPU */ static struct omap_hwmod_irq_info omap2xxx_mpu_irqs[] = { - { .name = "pmu", .irq = 3 }, + { .name = "pmu", .irq = 3 + OMAP_INTC_START }, { .irq = -1 } }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 285777241d5a..f67b7ee07dd4 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -94,7 +94,7 @@ static struct omap_hwmod omap3xxx_l4_sec_hwmod = { /* MPU */ static struct omap_hwmod_irq_info omap3xxx_mpu_irqs[] = { - { .name = "pmu", .irq = 3 }, + { .name = "pmu", .irq = 3 + OMAP_INTC_START }, { .irq = -1 } }; @@ -3683,6 +3683,7 @@ static struct omap_hwmod_ocp_if *am35xx_hwmod_ocp_ifs[] __initdata = { &omap3xxx_l4_core__usb_tll_hs, &omap3xxx_l4_core__es3plus_mmc1, &omap3xxx_l4_core__es3plus_mmc2, + &omap3xxx_l4_core__hdq1w, &am35xx_mdio__l3, &am35xx_l4_core__mdio, &am35xx_emac__l3, @@ -3737,7 +3738,7 @@ int __init omap3xxx_hwmod_init(void) } else { WARN(1, "OMAP3 hwmod family init: unknown chip type\n"); return -EINVAL; - }; + } r = omap_hwmod_register_links(h); if (r < 0) @@ -3754,7 +3755,7 @@ int __init omap3xxx_hwmod_init(void) rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2) { h = omap3430es2plus_hwmod_ocp_ifs; - }; + } if (h) { r = omap_hwmod_register_links(h); @@ -3769,7 +3770,7 @@ int __init omap3xxx_hwmod_init(void) } else if (rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2) { h = omap3430_es3plus_hwmod_ocp_ifs; - }; + } if (h) r = omap_hwmod_register_links(h); diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c index 45ad7f74f356..58e16aef40bb 100644 --- a/arch/arm/mach-omap2/opp.c +++ b/arch/arm/mach-omap2/opp.c @@ -18,6 +18,7 @@ */ #include <linux/module.h> #include <linux/opp.h> +#include <linux/cpu.h> #include <plat/omap_device.h> @@ -62,13 +63,23 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, __func__, i); return -EINVAL; } - oh = omap_hwmod_lookup(opp_def->hwmod_name); - if (!oh || !oh->od) { - pr_debug("%s: no hwmod or odev for %s, [%d] cannot add OPPs.\n", - __func__, opp_def->hwmod_name, i); - continue; + + if (!strncmp(opp_def->hwmod_name, "mpu", 3)) { + /* + * All current OMAPs share voltage rail and + * clock source, so CPU0 is used to represent + * the MPU-SS. + */ + dev = get_cpu_device(0); + } else { + oh = omap_hwmod_lookup(opp_def->hwmod_name); + if (!oh || !oh->od) { + pr_debug("%s: no hwmod or odev for %s, [%d] cannot add OPPs.\n", + __func__, opp_def->hwmod_name, i); + continue; + } + dev = &oh->od->pdev->dev; } - dev = &oh->od->pdev->dev; r = opp_add(dev, opp_def->freq, opp_def->u_volt); if (r) { diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 3e1345fc0713..46092cd806fa 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -168,7 +168,7 @@ static int pm_dbg_open(struct inode *inode, struct file *file) default: return single_open(file, pm_dbg_show_timers, &inode->i_private); - }; + } } static const struct file_operations debug_fops = { diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index abefbc4d8e0b..ea61c32957bd 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -16,6 +16,7 @@ #include <linux/opp.h> #include <linux/export.h> #include <linux/suspend.h> +#include <linux/cpu.h> #include <asm/system_misc.h> @@ -169,7 +170,15 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, goto exit; } - dev = omap_device_get_by_hwmod_name(oh_name); + if (!strncmp(oh_name, "mpu", 3)) + /* + * All current OMAPs share voltage rail and clock + * source, so CPU0 is used to represent the MPU-SS. + */ + dev = get_cpu_device(0); + else + dev = omap_device_get_by_hwmod_name(oh_name); + if (IS_ERR(dev)) { pr_err("%s: Unable to get dev pointer for hwmod %s\n", __func__, oh_name); @@ -177,7 +186,7 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, } voltdm = voltdm_lookup(vdd_name); - if (IS_ERR(voltdm)) { + if (!voltdm) { pr_err("%s: unable to get vdd pointer for vdd_%s\n", __func__, vdd_name); goto exit; diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index cbeae56b56a9..f8217a5a4a26 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -122,7 +122,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) sr_data->senp_mod = 0x1; sr_data->voltdm = voltdm_lookup(sr_dev_attr->sensor_voltdm_name); - if (IS_ERR(sr_data->voltdm)) { + if (!sr_data->voltdm) { pr_err("%s: Unable to get voltage domain pointer for VDD %s\n", __func__, sr_dev_attr->sensor_voltdm_name); goto exit; diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 8847d6eb2313..44f9aa7ec0c0 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -378,7 +378,7 @@ static void __init realtime_counter_init(void) return; } sys_clk = clk_get(NULL, "sys_clkin_ck"); - if (!sys_clk) { + if (IS_ERR(sys_clk)) { pr_err("%s: failed to get system clock handle\n", __func__); iounmap(base); return; diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 18a851959425..635e109f5ad3 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -158,7 +158,7 @@ static struct regulator_init_data omap3_vpll2_idata = { }; static struct regulator_consumer_supply omap3_vdd1_supply[] = { - REGULATOR_SUPPLY("vcc", "mpu.0"), + REGULATOR_SUPPLY("vcc", "cpu0"), }; static struct regulator_consumer_supply omap3_vdd2_supply[] = { @@ -239,6 +239,10 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, static struct twl4030_usb_data omap4_usb_pdata = { }; +static struct regulator_consumer_supply omap4_vdda_hdmi_dac_supplies[] = { + REGULATOR_SUPPLY("vdda_hdmi_dac", "omapdss_hdmi"), +}; + static struct regulator_init_data omap4_vdac_idata = { .constraints = { .min_uV = 1800000, @@ -248,6 +252,8 @@ static struct regulator_init_data omap4_vdac_idata = { .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, }, + .num_consumer_supplies = ARRAY_SIZE(omap4_vdda_hdmi_dac_supplies), + .consumer_supplies = omap4_vdda_hdmi_dac_supplies, .supply_regulator = "V2V1", }; diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c index fc3afc7cd366..a103c8ffea9f 100644 --- a/arch/arm/mach-pxa/cm-x2xx.c +++ b/arch/arm/mach-pxa/cm-x2xx.c @@ -22,6 +22,7 @@ #include <asm/mach/map.h> #include <mach/pxa25x.h> +#undef GPIO24_SSP1_SFRM #include <mach/pxa27x.h> #include <mach/audio.h> #include <linux/platform_data/video-pxafb.h> diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c index 997e6da9a9c4..32e0d7998355 100644 --- a/arch/arm/mach-pxa/palmte2.c +++ b/arch/arm/mach-pxa/palmte2.c @@ -105,6 +105,7 @@ static struct pxamci_platform_data palmte2_mci_platform_data = { .gpio_power = GPIO_NR_PALMTE2_SD_POWER, }; +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) /****************************************************************************** * GPIO keys ******************************************************************************/ @@ -132,6 +133,7 @@ static struct platform_device palmte2_pxa_keys = { .platform_data = &palmte2_pxa_keys_data, }, }; +#endif /****************************************************************************** * Backlight diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 5a406f794798..ec55c575ed19 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -55,7 +55,6 @@ #ifdef CONFIG_PM static int sharpsl_off_charge_battery(void); static int sharpsl_check_battery_voltage(void); -static int sharpsl_fatal_check(void); #endif static int sharpsl_check_battery_temp(void); static int sharpsl_ac_check(void); @@ -686,53 +685,6 @@ static int corgi_pxa_pm_enter(suspend_state_t state) return 0; } -/* - * Check for fatal battery errors - * Fatal returns -1 - */ -static int sharpsl_fatal_check(void) -{ - int buff[5], temp, i, acin; - - dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n"); - - /* Check AC-Adapter */ - acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); - - if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { - sharpsl_pm.machinfo->charge(0); - udelay(100); - sharpsl_pm.machinfo->discharge(1); /* enable discharge */ - mdelay(SHARPSL_WAIT_DISCHARGE_ON); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(1); - - /* Check battery : check inserting battery ? */ - for (i = 0; i < 5; i++) { - buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(0); - - if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { - udelay(100); - sharpsl_pm.machinfo->charge(1); - sharpsl_pm.machinfo->discharge(0); - } - - temp = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT)); - - if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) || - (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt))) - return -1; - return 0; -} - static int sharpsl_off_charge_error(void) { dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n"); diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index 392412ce4dac..c773e4dded64 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -768,8 +768,7 @@ static unsigned long viper_tpm; static int __init viper_tpm_setup(char *str) { - strict_strtoul(str, 10, &viper_tpm); - return 1; + return strict_strtoul(str, 10, &viper_tpm) >= 0; } __setup("tpm=", viper_tpm_setup); diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c index b91bc87b3dcf..fcb1d59f7aec 100644 --- a/arch/arm/mach-rpc/ecard.c +++ b/arch/arm/mach-rpc/ecard.c @@ -960,7 +960,9 @@ static int __init ecard_probe(int slot, unsigned irq, card_type_t type) *ecp = ec; slot_to_expcard[slot] = ec; - device_register(&ec->dev); + rc = device_register(&ec->dev); + if (rc) + goto nodev; return 0; diff --git a/arch/arm/mach-s3c24xx/irq-s3c2416.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c index 23ec97370f32..ff141b0af26b 100644 --- a/arch/arm/mach-s3c24xx/irq-s3c2416.c +++ b/arch/arm/mach-s3c24xx/irq-s3c2416.c @@ -232,7 +232,7 @@ struct irq_chip s3c2416_irq_second = { /* IRQ initialisation code */ -static int __init s3c2416_add_sub(unsigned int base, +static int s3c2416_add_sub(unsigned int base, void (*demux)(unsigned int, struct irq_desc *), struct irq_chip *chip, @@ -251,7 +251,7 @@ static int __init s3c2416_add_sub(unsigned int base, return 0; } -static void __init s3c2416_irq_add_second(void) +static void s3c2416_irq_add_second(void) { unsigned long pend; unsigned long last; @@ -287,7 +287,7 @@ static void __init s3c2416_irq_add_second(void) } } -static int __init s3c2416_irq_add(struct device *dev, +static int s3c2416_irq_add(struct device *dev, struct subsys_interface *sif) { printk(KERN_INFO "S3C2416: IRQ Support\n"); diff --git a/arch/arm/mach-s3c24xx/irq-s3c2443.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c index ac2829f56d12..5e69109c0928 100644 --- a/arch/arm/mach-s3c24xx/irq-s3c2443.c +++ b/arch/arm/mach-s3c24xx/irq-s3c2443.c @@ -222,7 +222,7 @@ static struct irq_chip s3c2443_irq_cam = { /* IRQ initialisation code */ -static int __init s3c2443_add_sub(unsigned int base, +static int s3c2443_add_sub(unsigned int base, void (*demux)(unsigned int, struct irq_desc *), struct irq_chip *chip, @@ -241,7 +241,7 @@ static int __init s3c2443_add_sub(unsigned int base, return 0; } -static int __init s3c2443_irq_add(struct device *dev, +static int s3c2443_irq_add(struct device *dev, struct subsys_interface *sif) { printk("S3C2443: IRQ Support\n"); diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c index db2787aa1e5e..f30d7fccbfee 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2416.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c @@ -29,6 +29,7 @@ #include <asm/mach/map.h> #include <asm/mach/irq.h> +#include <video/samsung_fimd.h> #include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach-types.h> @@ -52,7 +53,6 @@ #include <linux/platform_data/usb-s3c2410_udc.h> #include <linux/platform_data/s3c-hsudc.h> -#include <plat/regs-fb-v4.h> #include <plat/fb.h> #include <plat/common-smdk.h> diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c index 17f8356177c1..ddf7a3c743ac 100644 --- a/arch/arm/mach-s3c24xx/simtec-usb.c +++ b/arch/arm/mach-s3c24xx/simtec-usb.c @@ -104,7 +104,7 @@ static struct s3c2410_hcd_info usb_simtec_info __initdata = { }; -int usb_simtec_init(void) +int __init usb_simtec_init(void) { int ret; diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c index 15c58dfc4584..99e82ac81b69 100644 --- a/arch/arm/mach-s3c64xx/mach-anw6410.c +++ b/arch/arm/mach-s3c64xx/mach-anw6410.c @@ -29,6 +29,7 @@ #include <linux/dm9000.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <asm/hardware/vic.h> #include <asm/mach/arch.h> @@ -44,7 +45,6 @@ #include <plat/regs-serial.h> #include <linux/platform_data/i2c-s3c2410.h> #include <plat/fb.h> -#include <plat/regs-fb-v4.h> #include <plat/clock.h> #include <plat/devs.h> diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 8b4d46706645..13b7eaa45fd0 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -46,6 +46,7 @@ #include <asm/mach/arch.h> #include <asm/mach-types.h> +#include <video/samsung_fimd.h> #include <mach/hardware.h> #include <mach/map.h> @@ -57,7 +58,6 @@ #include <mach/regs-gpio-memport.h> #include <plat/regs-serial.h> -#include <plat/regs-fb-v4.h> #include <plat/fb.h> #include <plat/sdhci.h> #include <plat/gpio-cfg.h> diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c index 02222b32b7d3..2b144893ddc4 100644 --- a/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/arch/arm/mach-s3c64xx/mach-hmt.c @@ -26,6 +26,7 @@ #include <asm/mach/map.h> #include <asm/mach/irq.h> +#include <video/samsung_fimd.h> #include <mach/hardware.h> #include <mach/map.h> @@ -41,7 +42,6 @@ #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> -#include <plat/regs-fb-v4.h> #include "common.h" diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c index 09311cc40115..07c349cca333 100644 --- a/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -41,9 +41,9 @@ #include <linux/platform_data/mtd-nand-s3c2410.h> #include <plat/regs-serial.h> #include <linux/platform_data/touchscreen-s3c2410.h> -#include <plat/regs-fb-v4.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include "common.h" diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c index 46ee88d16815..e5f9a79b535d 100644 --- a/arch/arm/mach-s3c64xx/mach-ncp.c +++ b/arch/arm/mach-s3c64xx/mach-ncp.c @@ -24,6 +24,7 @@ #include <linux/delay.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <asm/hardware/vic.h> #include <asm/mach/arch.h> @@ -43,7 +44,6 @@ #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> -#include <plat/regs-fb-v4.h> #include "common.h" diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index 6daca203e72b..7476f7c722ab 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -42,9 +42,9 @@ #include <linux/platform_data/mtd-nand-s3c2410.h> #include <plat/regs-serial.h> #include <linux/platform_data/touchscreen-s3c2410.h> -#include <plat/regs-fb-v4.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include "common.h" diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c index d6266d8b43c9..96d6da2b6b5f 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq5.c +++ b/arch/arm/mach-s3c64xx/mach-smartq5.c @@ -21,6 +21,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <video/samsung_fimd.h> #include <mach/map.h> #include <mach/regs-gpio.h> @@ -28,7 +29,6 @@ #include <plat/devs.h> #include <plat/fb.h> #include <plat/gpio-cfg.h> -#include <plat/regs-fb-v4.h> #include "common.h" #include "mach-smartq.h" diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c index 0957d2a980e1..7d1167bdc921 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq7.c +++ b/arch/arm/mach-s3c64xx/mach-smartq7.c @@ -21,6 +21,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <video/samsung_fimd.h> #include <mach/map.h> #include <mach/regs-gpio.h> @@ -28,7 +29,6 @@ #include <plat/devs.h> #include <plat/fb.h> #include <plat/gpio-cfg.h> -#include <plat/regs-fb-v4.h> #include "common.h" #include "mach-smartq.h" diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index 2547a8846472..da1a771a29e9 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -43,6 +43,7 @@ #endif #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <asm/hardware/vic.h> #include <asm/mach/arch.h> @@ -72,7 +73,6 @@ #include <linux/platform_data/touchscreen-s3c2410.h> #include <plat/keypad.h> #include <plat/backlight.h> -#include <plat/regs-fb-v4.h> #include "common.h" diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c index dea78a848244..96ea1fe0ec94 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -27,6 +27,7 @@ #include <linux/mmc/host.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <asm/hardware/vic.h> #include <asm/mach/arch.h> @@ -52,7 +53,6 @@ #include <plat/s5p-time.h> #include <plat/backlight.h> #include <plat/fb.h> -#include <plat/regs-fb.h> #include <plat/sdhci.h> #include "common.h" diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c index 6f14fc729b8f..12748b6eaa7b 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -27,6 +27,7 @@ #include <linux/mmc/host.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <asm/hardware/vic.h> #include <asm/mach/arch.h> @@ -52,7 +53,6 @@ #include <plat/s5p-time.h> #include <plat/backlight.h> #include <plat/fb.h> -#include <plat/regs-fb.h> #include <plat/sdhci.h> #include "common.h" diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c index 5d2c0934928b..dba7384a87bd 100644 --- a/arch/arm/mach-s5pc100/mach-smdkc100.c +++ b/arch/arm/mach-s5pc100/mach-smdkc100.c @@ -33,6 +33,7 @@ #include <mach/regs-gpio.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <asm/irq.h> #include <asm/mach-types.h> @@ -51,7 +52,6 @@ #include <linux/platform_data/touchscreen-s3c2410.h> #include <linux/platform_data/asoc-s3c.h> #include <plat/backlight.h> -#include <plat/regs-fb-v4.h> #include "common.h" diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c index 78028df86c5d..ee9fa5c2ef2c 100644 --- a/arch/arm/mach-s5pv210/mach-aquila.c +++ b/arch/arm/mach-s5pv210/mach-aquila.c @@ -28,6 +28,7 @@ #include <asm/setup.h> #include <asm/mach-types.h> +#include <video/samsung_fimd.h> #include <mach/map.h> #include <mach/regs-clock.h> @@ -39,7 +40,6 @@ #include <plat/fimc-core.h> #include <plat/sdhci.h> #include <plat/s5p-time.h> -#include <plat/regs-fb-v4.h> #include "common.h" diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c index 00f1e47d490a..55e1dba4ffde 100644 --- a/arch/arm/mach-s5pv210/mach-goni.c +++ b/arch/arm/mach-s5pv210/mach-goni.c @@ -35,6 +35,7 @@ #include <asm/setup.h> #include <asm/mach-types.h> +#include <video/samsung_fimd.h> #include <mach/map.h> #include <mach/regs-clock.h> @@ -49,7 +50,6 @@ #include <plat/clock.h> #include <plat/s5p-time.h> #include <plat/mfc.h> -#include <plat/regs-fb-v4.h> #include <plat/camport.h> #include <media/v4l2-mediabus.h> diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index 7d6fab420508..4cdb5bb7bbcf 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -28,6 +28,7 @@ #include <asm/mach-types.h> #include <video/platform_lcd.h> +#include <video/samsung_fimd.h> #include <mach/map.h> #include <mach/regs-clock.h> @@ -46,7 +47,6 @@ #include <plat/fb.h> #include <plat/s5p-time.h> #include <plat/backlight.h> -#include <plat/regs-fb-v4.h> #include <plat/mfc.h> #include <plat/clock.h> diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index e1ccda6128eb..6a7ad3c2a3fc 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -388,7 +388,7 @@ static void __init map_sa1100_gpio_regs( void ) */ static void __init get_assabet_scr(void) { - unsigned long scr, i; + unsigned long uninitialized_var(scr), i; GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ diff --git a/arch/arm/mach-shark/pci.c b/arch/arm/mach-shark/pci.c index b8b4ab323a3e..6d91a914c1dd 100644 --- a/arch/arm/mach-shark/pci.c +++ b/arch/arm/mach-shark/pci.c @@ -41,7 +41,7 @@ static struct hw_pci shark_pci __initdata = { static int __init shark_pci_init(void) { if (!machine_is_shark()) - return; + return -ENODEV; pcibios_min_io = 0x6000; pcibios_min_mem = 0x50000000; diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index ed77ab8c9143..d47e215aca87 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -100,7 +100,7 @@ static inline int shmobile_cpu_is_dead(unsigned int cpu) { return 1; } extern void shmobile_smp_init_cpus(unsigned int ncores); -static inline void shmobile_init_late(void) +static inline void __init shmobile_init_late(void) { shmobile_suspend_init(); shmobile_cpuidle_init(); diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 5f3c03b61f8e..11680c532b38 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -16,7 +16,7 @@ config ARCH_TEGRA_2x_SOC select ARM_ERRATA_742230 select ARM_ERRATA_751472 select ARM_ERRATA_754327 - select ARM_ERRATA_764369 + select ARM_ERRATA_764369 if SMP select PL310_ERRATA_727915 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0 select CPU_FREQ_TABLE if CPU_FREQ @@ -37,7 +37,7 @@ config ARCH_TEGRA_3x_SOC select ARM_ERRATA_743622 select ARM_ERRATA_751472 select ARM_ERRATA_754322 - select ARM_ERRATA_764369 + select ARM_ERRATA_764369 if SMP select PL310_ERRATA_769419 if CACHE_L2X0 select CPU_FREQ_TABLE if CPU_FREQ help @@ -57,8 +57,6 @@ config TEGRA_AHB which controls AHB bus master arbitration and some perfomance parameters(priority, prefech size). -comment "Tegra board type" - choice prompt "Default low-level debug console UART" default TEGRA_DEBUG_UART_NONE diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index c77c86c47369..5848206ee9b9 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -5,9 +5,9 @@ config UX500_SOC_COMMON default y select ARM_GIC select HAS_MTU - select PL310_ERRATA_753970 + select PL310_ERRATA_753970 if CACHE_PL310 select ARM_ERRATA_754322 - select ARM_ERRATA_764369 + select ARM_ERRATA_764369 if SMP select CACHE_L2X0 select PINCTRL select PINCTRL_NOMADIK diff --git a/arch/arm/mach-vt8500/include/mach/uncompress.h b/arch/arm/mach-vt8500/include/mach/uncompress.h index bb9e2d23fee3..e6e81fdaf109 100644 --- a/arch/arm/mach-vt8500/include/mach/uncompress.h +++ b/arch/arm/mach-vt8500/include/mach/uncompress.h @@ -15,15 +15,15 @@ * */ -#define UART0_PHYS 0xd8200000 -#include <asm/io.h> +#define UART0_PHYS 0xd8200000 +#define UART0_ADDR(x) *(volatile unsigned char *)(UART0_PHYS + x) static void putc(const char c) { - while (readb(UART0_PHYS + 0x1c) & 0x2) + while (UART0_ADDR(0x1c) & 0x2) /* Tx busy, wait and poll */; - writeb(c, UART0_PHYS); + UART0_ADDR(0) = c; } static void flush(void) diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c index 587ea950d08b..8d3871f110a5 100644 --- a/arch/arm/mach-vt8500/vt8500.c +++ b/arch/arm/mach-vt8500/vt8500.c @@ -77,8 +77,11 @@ static void vt8500_power_off(void) void __init vt8500_init(void) { - struct device_node *np, *fb; + struct device_node *np; +#if defined(CONFIG_FB_VT8500) || defined(CONFIG_FB_WM8505) + struct device_node *fb; void __iomem *gpio_base; +#endif #ifdef CONFIG_FB_VT8500 fb = of_find_compatible_node(NULL, NULL, "via,vt8500-fb"); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 101b9681c08c..c9a4963b5c3d 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -624,6 +624,23 @@ config ARM_THUMBEE Say Y here if you have a CPU with the ThumbEE extension and code to make use of it. Say N for code that can run on CPUs without ThumbEE. +config ARM_VIRT_EXT + bool "Native support for the ARM Virtualization Extensions" + depends on MMU && CPU_V7 + help + Enable the kernel to make use of the ARM Virtualization + Extensions to install hypervisors without run-time firmware + assistance. + + A compliant bootloader is required in order to make maximum + use of this feature. Refer to Documentation/arm/Booting for + details. + + It is safe to enable this option even if the kernel may not be + booted in HYP mode, may not have support for the + virtualization extensions, or may be booted with a + non-compliant bootloader. + config SWP_EMULATE bool "Emulate SWP/SWPB instructions" depends on !CPU_USE_DOMAINS && CPU_V7 diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S index 072016371093..e505befe51b5 100644 --- a/arch/arm/mm/cache-fa.S +++ b/arch/arm/mm/cache-fa.S @@ -240,6 +240,9 @@ ENTRY(fa_dma_unmap_area) mov pc, lr ENDPROC(fa_dma_unmap_area) + .globl fa_flush_kern_cache_louis + .equ fa_flush_kern_cache_louis, fa_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index 52e35f32eefb..8a3fadece8d3 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S @@ -128,6 +128,9 @@ ENTRY(v3_dma_map_area) ENDPROC(v3_dma_unmap_area) ENDPROC(v3_dma_map_area) + .globl v3_flush_kern_cache_louis + .equ v3_flush_kern_cache_louis, v3_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index 022135d2b7e4..43e5d77be677 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S @@ -140,6 +140,9 @@ ENTRY(v4_dma_map_area) ENDPROC(v4_dma_unmap_area) ENDPROC(v4_dma_map_area) + .globl v4_flush_kern_cache_louis + .equ v4_flush_kern_cache_louis, v4_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index 8f1eeae340c8..cd4945321407 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S @@ -251,6 +251,9 @@ ENTRY(v4wb_dma_unmap_area) mov pc, lr ENDPROC(v4wb_dma_unmap_area) + .globl v4wb_flush_kern_cache_louis + .equ v4wb_flush_kern_cache_louis, v4wb_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S index b34a5f908a82..11e5e5838bc5 100644 --- a/arch/arm/mm/cache-v4wt.S +++ b/arch/arm/mm/cache-v4wt.S @@ -196,6 +196,9 @@ ENTRY(v4wt_dma_map_area) ENDPROC(v4wt_dma_unmap_area) ENDPROC(v4wt_dma_map_area) + .globl v4wt_flush_kern_cache_louis + .equ v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 4b10760c56d6..d8fd4d4bd3d4 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -326,6 +326,9 @@ ENTRY(v6_dma_unmap_area) mov pc, lr ENDPROC(v6_dma_unmap_area) + .globl v6_flush_kern_cache_louis + .equ v6_flush_kern_cache_louis, v6_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index 3b172275262e..cd956647c21a 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -33,6 +33,24 @@ ENTRY(v7_flush_icache_all) mov pc, lr ENDPROC(v7_flush_icache_all) + /* + * v7_flush_dcache_louis() + * + * Flush the D-cache up to the Level of Unification Inner Shareable + * + * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) + */ + +ENTRY(v7_flush_dcache_louis) + dmb @ ensure ordering with previous memory accesses + mrc p15, 1, r0, c0, c0, 1 @ read clidr, r0 = clidr + ands r3, r0, #0xe00000 @ extract LoUIS from clidr + mov r3, r3, lsr #20 @ r3 = LoUIS * 2 + moveq pc, lr @ return if level == 0 + mov r10, #0 @ r10 (starting level) = 0 + b flush_levels @ start flushing cache levels +ENDPROC(v7_flush_dcache_louis) + /* * v7_flush_dcache_all() * @@ -49,7 +67,7 @@ ENTRY(v7_flush_dcache_all) mov r3, r3, lsr #23 @ left align loc bit field beq finished @ if loc is 0, then no need to clean mov r10, #0 @ start clean at cache level 0 -loop1: +flush_levels: add r2, r10, r10, lsr #1 @ work out 3x current cache level mov r1, r0, lsr r2 @ extract cache type bits from clidr and r1, r1, #7 @ mask of the bits for current cache only @@ -71,9 +89,9 @@ loop1: clz r5, r4 @ find bit position of way size increment ldr r7, =0x7fff ands r7, r7, r1, lsr #13 @ extract max number of the index size -loop2: +loop1: mov r9, r4 @ create working copy of max way size -loop3: +loop2: ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11 THUMB( lsl r6, r9, r5 ) THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 @@ -82,13 +100,13 @@ loop3: THUMB( orr r11, r11, r6 ) @ factor index number into r11 mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way subs r9, r9, #1 @ decrement the way - bge loop3 - subs r7, r7, #1 @ decrement the index bge loop2 + subs r7, r7, #1 @ decrement the index + bge loop1 skip: add r10, r10, #2 @ increment cache number cmp r3, r10 - bgt loop1 + bgt flush_levels finished: mov r10, #0 @ swith back to cache level 0 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr @@ -120,6 +138,24 @@ ENTRY(v7_flush_kern_cache_all) mov pc, lr ENDPROC(v7_flush_kern_cache_all) + /* + * v7_flush_kern_cache_louis(void) + * + * Flush the data cache up to Level of Unification Inner Shareable. + * Invalidate the I-cache to the point of unification. + */ +ENTRY(v7_flush_kern_cache_louis) + ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) + THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) + bl v7_flush_dcache_louis + mov r0, #0 + ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable + ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate + ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) + THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) + mov pc, lr +ENDPROC(v7_flush_kern_cache_louis) + /* * v7_flush_cache_all() * diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 0650bb87c1e3..2bb61e703d6c 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -368,6 +368,9 @@ ENTRY(arm1020_dma_unmap_area) mov pc, lr ENDPROC(arm1020_dma_unmap_area) + .globl arm1020_flush_kern_cache_louis + .equ arm1020_flush_kern_cache_louis, arm1020_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1020 diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index 4188478325a6..8f96aa40f510 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -354,6 +354,9 @@ ENTRY(arm1020e_dma_unmap_area) mov pc, lr ENDPROC(arm1020e_dma_unmap_area) + .globl arm1020e_flush_kern_cache_louis + .equ arm1020e_flush_kern_cache_louis, arm1020e_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1020e diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 33c68824bff0..8ebe4a469a22 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -343,6 +343,9 @@ ENTRY(arm1022_dma_unmap_area) mov pc, lr ENDPROC(arm1022_dma_unmap_area) + .globl arm1022_flush_kern_cache_louis + .equ arm1022_flush_kern_cache_louis, arm1022_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1022 diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index fbc1d5fc24dc..093fc7e520c3 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -337,6 +337,9 @@ ENTRY(arm1026_dma_unmap_area) mov pc, lr ENDPROC(arm1026_dma_unmap_area) + .globl arm1026_flush_kern_cache_louis + .equ arm1026_flush_kern_cache_louis, arm1026_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1026 diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 1a8c138eb897..2c3b9421ab5e 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -319,6 +319,9 @@ ENTRY(arm920_dma_unmap_area) mov pc, lr ENDPROC(arm920_dma_unmap_area) + .globl arm920_flush_kern_cache_louis + .equ arm920_flush_kern_cache_louis, arm920_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm920 #endif diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 4c44d7e1c3ca..4464c49d7449 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -321,6 +321,9 @@ ENTRY(arm922_dma_unmap_area) mov pc, lr ENDPROC(arm922_dma_unmap_area) + .globl arm922_flush_kern_cache_louis + .equ arm922_flush_kern_cache_louis, arm922_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm922 #endif diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index ec5b1180994f..281eb9b9c1d6 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -376,6 +376,9 @@ ENTRY(arm925_dma_unmap_area) mov pc, lr ENDPROC(arm925_dma_unmap_area) + .globl arm925_flush_kern_cache_louis + .equ arm925_flush_kern_cache_louis, arm925_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm925 diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index c31e62c606c0..f1803f7e2972 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -339,6 +339,9 @@ ENTRY(arm926_dma_unmap_area) mov pc, lr ENDPROC(arm926_dma_unmap_area) + .globl arm926_flush_kern_cache_louis + .equ arm926_flush_kern_cache_louis, arm926_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm926 diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S index a613a7dd7146..8da189d4a402 100644 --- a/arch/arm/mm/proc-arm940.S +++ b/arch/arm/mm/proc-arm940.S @@ -267,6 +267,9 @@ ENTRY(arm940_dma_unmap_area) mov pc, lr ENDPROC(arm940_dma_unmap_area) + .globl arm940_flush_kern_cache_louis + .equ arm940_flush_kern_cache_louis, arm940_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm940 diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S index 9f4f2999fdd0..f666cf34075a 100644 --- a/arch/arm/mm/proc-arm946.S +++ b/arch/arm/mm/proc-arm946.S @@ -310,6 +310,9 @@ ENTRY(arm946_dma_unmap_area) mov pc, lr ENDPROC(arm946_dma_unmap_area) + .globl arm946_flush_kern_cache_louis + .equ arm946_flush_kern_cache_louis, arm946_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm946 diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S index 23a8e4c7f2bd..4106b09e0c29 100644 --- a/arch/arm/mm/proc-feroceon.S +++ b/arch/arm/mm/proc-feroceon.S @@ -415,6 +415,9 @@ ENTRY(feroceon_dma_unmap_area) mov pc, lr ENDPROC(feroceon_dma_unmap_area) + .globl feroceon_flush_kern_cache_louis + .equ feroceon_flush_kern_cache_louis, feroceon_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions feroceon @@ -431,6 +434,7 @@ ENDPROC(feroceon_dma_unmap_area) range_alias flush_icache_all range_alias flush_user_cache_all range_alias flush_kern_cache_all + range_alias flush_kern_cache_louis range_alias flush_user_cache_range range_alias coherent_kern_range range_alias coherent_user_range diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 2d8ff3ad86d3..b29a2265af01 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -299,6 +299,7 @@ ENTRY(\name\()_processor_functions) ENTRY(\name\()_cache_fns) .long \name\()_flush_icache_all .long \name\()_flush_kern_cache_all + .long \name\()_flush_kern_cache_louis .long \name\()_flush_user_cache_all .long \name\()_flush_user_cache_range .long \name\()_coherent_kern_range diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S index fbb2124a547d..82f9cdc751d6 100644 --- a/arch/arm/mm/proc-mohawk.S +++ b/arch/arm/mm/proc-mohawk.S @@ -303,6 +303,9 @@ ENTRY(mohawk_dma_unmap_area) mov pc, lr ENDPROC(mohawk_dma_unmap_area) + .globl mohawk_flush_kern_cache_louis + .equ mohawk_flush_kern_cache_louis, mohawk_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions mohawk diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index c2e2b66f72b5..846d279f3176 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -172,7 +172,7 @@ __v7_ca15mp_setup: __v7_setup: adr r12, __v7_setup_stack @ the local stack stmia r12, {r0-r5, r7, r9, r11, lr} - bl v7_flush_dcache_all + bl v7_flush_dcache_louis ldmia r12, {r0-r5, r7, r9, r11, lr} mrc p15, 0, r0, c0, c0, 0 @ read main ID register diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index b0d57869da2d..eb93d6487f35 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -337,6 +337,9 @@ ENTRY(xsc3_dma_unmap_area) mov pc, lr ENDPROC(xsc3_dma_unmap_area) + .globl xsc3_flush_kern_cache_louis + .equ xsc3_flush_kern_cache_louis, xsc3_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions xsc3 diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 4ffebaa595ee..25510361aa18 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -410,6 +410,9 @@ ENTRY(xscale_dma_unmap_area) mov pc, lr ENDPROC(xscale_dma_unmap_area) + .globl xscale_flush_kern_cache_louis + .equ xscale_flush_kern_cache_louis, xscale_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions xscale @@ -439,6 +442,7 @@ ENDPROC(xscale_dma_unmap_area) a0_alias flush_icache_all a0_alias flush_user_cache_all a0_alias flush_kern_cache_all + a0_alias flush_kern_cache_louis a0_alias flush_user_cache_range a0_alias coherent_kern_range a0_alias coherent_user_range diff --git a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h index 826de74bfdd1..c08a54d9d889 100644 --- a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h +++ b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h @@ -45,6 +45,12 @@ #define NMK_GPIO_ALT_B 2 #define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) +#define NMK_GPIO_ALT_CX_SHIFT 2 +#define NMK_GPIO_ALT_C1 ((1<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C2 ((2<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C3 ((3<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C4 ((4<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) + /* Pull up/down values */ enum nmk_gpio_pull { NMK_GPIO_PULL_NONE, diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h index 9c949c7c98a7..3b8ec60af351 100644 --- a/arch/arm/plat-nomadik/include/plat/pincfg.h +++ b/arch/arm/plat-nomadik/include/plat/pincfg.h @@ -25,6 +25,8 @@ * bit 19..20 - SLPM direction * bit 21..22 - SLPM Value (if output) * bit 23..25 - PDIS value (if input) + * bit 26 - Gpio mode + * bit 27 - Sleep mode * * to facilitate the definition, the following macros are provided * diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index ca83a7659aef..c9d1c3603bbf 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -43,11 +43,13 @@ config OMAP_DEBUG_DEVICES config OMAP_DEBUG_LEDS def_bool y if NEW_LEDS + select LEDS_CLASS depends on OMAP_DEBUG_DEVICES config POWER_AVS_OMAP bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2" depends on POWER_AVS && (ARCH_OMAP3 || ARCH_OMAP4) && PM + select POWER_SUPPLY help Say Y to enable AVS(Adaptive Voltage Scaling) support on OMAP containing the version 1 or diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index 2e826f1faf7b..87ba8dd0d791 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c @@ -52,22 +52,29 @@ static u32 notrace omap_32k_read_sched_clock(void) * nsecs and adds to a monotonically increasing timespec. */ static struct timespec persistent_ts; -static cycles_t cycles, last_cycles; +static cycles_t cycles; static unsigned int persistent_mult, persistent_shift; +static DEFINE_SPINLOCK(read_persistent_clock_lock); + static void omap_read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; - cycles_t delta; - struct timespec *tsp = &persistent_ts; + cycles_t last_cycles; + unsigned long flags; + + spin_lock_irqsave(&read_persistent_clock_lock, flags); last_cycles = cycles; cycles = sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0; - delta = cycles - last_cycles; - nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); + nsecs = clocksource_cyc2ns(cycles - last_cycles, + persistent_mult, persistent_shift); + + timespec_add_ns(&persistent_ts, nsecs); + + *ts = persistent_ts; - timespec_add_ns(tsp, nsecs); - *ts = *tsp; + spin_unlock_irqrestore(&read_persistent_clock_lock, flags); } /** diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 6013831a043e..a5683a84c6ee 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,14 +26,12 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/i2c.h> -#include <linux/i2c-omap.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/clk.h> #include <mach/irqs.h> #include <plat/i2c.h> -#include <plat/omap-pm.h> #include <plat/omap_device.h> #define OMAP_I2C_SIZE 0x3f @@ -129,16 +127,6 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS -/* - * XXX This function is a temporary compatibility wrapper - only - * needed until the I2C driver can be converted to call - * omap_pm_set_max_dev_wakeup_lat() and handle a return code. - */ -static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) -{ - omap_pm_set_max_mpu_wakeup_lat(dev, t); -} - static inline int omap2_i2c_add_bus(int bus_id) { int l; @@ -170,15 +158,6 @@ static inline int omap2_i2c_add_bus(int bus_id) dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; pdata->flags = dev_attr->flags; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - * Only omap3 has support for constraints - */ - if (cpu_is_omap34xx()) - pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c index 9f6413324df9..9722f418ae1f 100644 --- a/arch/arm/plat-omap/omap-pm-noop.c +++ b/arch/arm/plat-omap/omap-pm-noop.c @@ -38,7 +38,7 @@ int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) if (!dev || t < -1) { WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); return -EINVAL; - }; + } if (t == -1) pr_debug("OMAP PM: remove max MPU wakeup latency constraint: dev %s\n", @@ -67,7 +67,7 @@ int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) agent_id != OCP_TARGET_AGENT)) { WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); return -EINVAL; - }; + } if (r == 0) pr_debug("OMAP PM: remove min bus tput constraint: dev %s for agent_id %d\n", @@ -93,7 +93,7 @@ int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, if (!req_dev || !dev || t < -1) { WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); return -EINVAL; - }; + } if (t == -1) pr_debug("OMAP PM: remove max device latency constraint: dev %s\n", @@ -123,7 +123,7 @@ int omap_pm_set_max_sdma_lat(struct device *dev, long t) if (!dev || t < -1) { WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); return -EINVAL; - }; + } if (t == -1) pr_debug("OMAP PM: remove max DMA latency constraint: dev %s\n", diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index cee85a55bd82..7a7d1f2a65e9 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -725,7 +725,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, int p dev_set_name(&pdev->dev, "%s", pdev->name); od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt); - if (!od) + if (IS_ERR(od)) goto odbs_exit1; ret = platform_device_add_data(pdev, pdata, pdata_len); diff --git a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h deleted file mode 100644 index 4c3647f80057..000000000000 --- a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h +++ /dev/null @@ -1,159 +0,0 @@ -/* arch/arm/plat-samsung/include/plat/regs-fb-v4.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks <ben@simtec.co.uk> - * - * S3C64XX - new-style framebuffer register definitions - * - * This is the register set for the new style framebuffer interface - * found from the S3C2443 onwards and specifically the S3C64XX series - * S3C6400 and S3C6410. - * - * The file contains the cpu specific items which change between whichever - * architecture is selected. See <plat/regs-fb.h> for the core definitions - * that are the same. - * - * 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 the core definitions here, in case we really do need to - * override them at a later date. -*/ - -#include <plat/regs-fb.h> - -#define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */ -#define VIDCON1_FSTATUS_EVEN (1 << 15) - -/* Video timing controls */ -#define VIDTCON0 (0x10) -#define VIDTCON1 (0x14) -#define VIDTCON2 (0x18) - -/* Window position controls */ - -#define WINCON(_win) (0x20 + ((_win) * 4)) - -/* OSD1 and OSD4 do not have register D */ - -#define VIDOSD_BASE (0x40) - -#define VIDINTCON0 (0x130) - -/* WINCONx */ - -#define WINCONx_CSCWIDTH_MASK (0x3 << 26) -#define WINCONx_CSCWIDTH_SHIFT (26) -#define WINCONx_CSCWIDTH_WIDE (0x0 << 26) -#define WINCONx_CSCWIDTH_NARROW (0x3 << 26) - -#define WINCONx_ENLOCAL (1 << 22) -#define WINCONx_BUFSTATUS (1 << 21) -#define WINCONx_BUFSEL (1 << 20) -#define WINCONx_BUFAUTOEN (1 << 19) -#define WINCONx_YCbCr (1 << 13) - -#define WINCON1_LOCALSEL_CAMIF (1 << 23) - -#define WINCON2_LOCALSEL_CAMIF (1 << 23) -#define WINCON2_BLD_PIX (1 << 6) - -#define WINCON2_ALPHA_SEL (1 << 1) -#define WINCON2_BPPMODE_MASK (0xf << 2) -#define WINCON2_BPPMODE_SHIFT (2) -#define WINCON2_BPPMODE_1BPP (0x0 << 2) -#define WINCON2_BPPMODE_2BPP (0x1 << 2) -#define WINCON2_BPPMODE_4BPP (0x2 << 2) -#define WINCON2_BPPMODE_8BPP_1232 (0x4 << 2) -#define WINCON2_BPPMODE_16BPP_565 (0x5 << 2) -#define WINCON2_BPPMODE_16BPP_A1555 (0x6 << 2) -#define WINCON2_BPPMODE_16BPP_I1555 (0x7 << 2) -#define WINCON2_BPPMODE_18BPP_666 (0x8 << 2) -#define WINCON2_BPPMODE_18BPP_A1665 (0x9 << 2) -#define WINCON2_BPPMODE_19BPP_A1666 (0xa << 2) -#define WINCON2_BPPMODE_24BPP_888 (0xb << 2) -#define WINCON2_BPPMODE_24BPP_A1887 (0xc << 2) -#define WINCON2_BPPMODE_25BPP_A1888 (0xd << 2) -#define WINCON2_BPPMODE_28BPP_A4888 (0xd << 2) - -#define WINCON3_BLD_PIX (1 << 6) - -#define WINCON3_ALPHA_SEL (1 << 1) -#define WINCON3_BPPMODE_MASK (0xf << 2) -#define WINCON3_BPPMODE_SHIFT (2) -#define WINCON3_BPPMODE_1BPP (0x0 << 2) -#define WINCON3_BPPMODE_2BPP (0x1 << 2) -#define WINCON3_BPPMODE_4BPP (0x2 << 2) -#define WINCON3_BPPMODE_16BPP_565 (0x5 << 2) -#define WINCON3_BPPMODE_16BPP_A1555 (0x6 << 2) -#define WINCON3_BPPMODE_16BPP_I1555 (0x7 << 2) -#define WINCON3_BPPMODE_18BPP_666 (0x8 << 2) -#define WINCON3_BPPMODE_18BPP_A1665 (0x9 << 2) -#define WINCON3_BPPMODE_19BPP_A1666 (0xa << 2) -#define WINCON3_BPPMODE_24BPP_888 (0xb << 2) -#define WINCON3_BPPMODE_24BPP_A1887 (0xc << 2) -#define WINCON3_BPPMODE_25BPP_A1888 (0xd << 2) -#define WINCON3_BPPMODE_28BPP_A4888 (0xd << 2) - -#define VIDINTCON0_FIFIOSEL_WINDOW2 (0x10 << 5) -#define VIDINTCON0_FIFIOSEL_WINDOW3 (0x20 << 5) -#define VIDINTCON0_FIFIOSEL_WINDOW4 (0x40 << 5) - -#define DITHMODE (0x170) -#define WINxMAP(_win) (0x180 + ((_win) * 4)) - - -#define DITHMODE_R_POS_MASK (0x3 << 5) -#define DITHMODE_R_POS_SHIFT (5) -#define DITHMODE_R_POS_8BIT (0x0 << 5) -#define DITHMODE_R_POS_6BIT (0x1 << 5) -#define DITHMODE_R_POS_5BIT (0x2 << 5) - -#define DITHMODE_G_POS_MASK (0x3 << 3) -#define DITHMODE_G_POS_SHIFT (3) -#define DITHMODE_G_POS_8BIT (0x0 << 3) -#define DITHMODE_G_POS_6BIT (0x1 << 3) -#define DITHMODE_G_POS_5BIT (0x2 << 3) - -#define DITHMODE_B_POS_MASK (0x3 << 1) -#define DITHMODE_B_POS_SHIFT (1) -#define DITHMODE_B_POS_8BIT (0x0 << 1) -#define DITHMODE_B_POS_6BIT (0x1 << 1) -#define DITHMODE_B_POS_5BIT (0x2 << 1) - -#define DITHMODE_DITH_EN (1 << 0) - -#define WPALCON (0x1A0) - -/* Palette control */ -/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L), - * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */ -#define WPALCON_W4PAL_16BPP_A555 (1 << 8) -#define WPALCON_W3PAL_16BPP_A555 (1 << 7) -#define WPALCON_W2PAL_16BPP_A555 (1 << 6) - - -/* Notes on per-window bpp settings - * - * Value Win0 Win1 Win2 Win3 Win 4 - * 0000 1(P) 1(P) 1(P) 1(P) 1(P) - * 0001 2(P) 2(P) 2(P) 2(P) 2(P) - * 0010 4(P) 4(P) 4(P) 4(P) -none- - * 0011 8(P) 8(P) -none- -none- -none- - * 0100 -none- 8(A232) 8(A232) -none- -none- - * 0101 16(565) 16(565) 16(565) 16(565) 16(565) - * 0110 -none- 16(A555) 16(A555) 16(A555) 16(A555) - * 0111 16(I555) 16(I565) 16(I555) 16(I555) 16(I555) - * 1000 18(666) 18(666) 18(666) 18(666) 18(666) - * 1001 -none- 18(A665) 18(A665) 18(A665) 16(A665) - * 1010 -none- 19(A666) 19(A666) 19(A666) 19(A666) - * 1011 24(888) 24(888) 24(888) 24(888) 24(888) - * 1100 -none- 24(A887) 24(A887) 24(A887) 24(A887) - * 1101 -none- 25(A888) 25(A888) 25(A888) 25(A888) - * 1110 -none- -none- -none- -none- -none- - * 1111 -none- -none- -none- -none- -none- -*/ diff --git a/arch/arm/plat-samsung/setup-mipiphy.c b/arch/arm/plat-samsung/setup-mipiphy.c index 683c466c0e6a..147459327601 100644 --- a/arch/arm/plat-samsung/setup-mipiphy.c +++ b/arch/arm/plat-samsung/setup-mipiphy.c @@ -14,24 +14,18 @@ #include <linux/spinlock.h> #include <mach/regs-clock.h> -static int __s5p_mipi_phy_control(struct platform_device *pdev, - bool on, u32 reset) +static int __s5p_mipi_phy_control(int id, bool on, u32 reset) { static DEFINE_SPINLOCK(lock); void __iomem *addr; unsigned long flags; - int pid; u32 cfg; - if (!pdev) + id = max(0, id); + if (id > 1) return -EINVAL; - pid = (pdev->id == -1) ? 0 : pdev->id; - - if (pid != 0 && pid != 1) - return -EINVAL; - - addr = S5P_MIPI_DPHY_CONTROL(pid); + addr = S5P_MIPI_DPHY_CONTROL(id); spin_lock_irqsave(&lock, flags); @@ -52,12 +46,12 @@ static int __s5p_mipi_phy_control(struct platform_device *pdev, return 0; } -int s5p_csis_phy_enable(struct platform_device *pdev, bool on) +int s5p_csis_phy_enable(int id, bool on) { - return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_SRESETN); + return __s5p_mipi_phy_control(id, on, S5P_MIPI_DPHY_SRESETN); } int s5p_dsim_phy_enable(struct platform_device *pdev, bool on) { - return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN); + return __s5p_mipi_phy_control(pdev->id, on, S5P_MIPI_DPHY_MRESETN); } diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c index 905fcfb0ddd0..b120df37de35 100644 --- a/arch/arm64/kernel/sys.c +++ b/arch/arm64/kernel/sys.c @@ -50,13 +50,13 @@ asmlinkage long sys_execve(const char __user *filenamei, struct pt_regs *regs) { long error; - char * filename; + struct filename *filename; filename = getname(filenamei); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); out: return error; diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index 93f10e27dc79..e521087cb0c4 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c @@ -56,14 +56,14 @@ asmlinkage int compat_sys_execve(const char __user *filenamei, struct pt_regs *regs) { int error; - char * filename; + struct filename *filename; filename = getname(filenamei); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = compat_do_execve(filename, compat_ptr(argv), compat_ptr(envp), - regs); + error = compat_do_execve(filename->name, compat_ptr(argv), + compat_ptr(envp), regs); putname(filename); out: return error; diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h index e5deda4691db..6dc62e1f94c7 100644 --- a/arch/avr32/include/asm/thread_info.h +++ b/arch/avr32/include/asm/thread_info.h @@ -77,8 +77,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling - TIF_NEED_RESCHED */ #define TIF_BREAKPOINT 4 /* enter monitor mode on return */ #define TIF_SINGLE_STEP 5 /* single step in progress */ #define TIF_MEMDIE 6 /* is terminating due to OOM killer */ @@ -91,10 +89,9 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) +#define _TIF_BREAKPOINT (1 << TIF_BREAKPOINT) #define _TIF_SINGLE_STEP (1 << TIF_SINGLE_STEP) #define _TIF_MEMDIE (1 << TIF_MEMDIE) -#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -102,17 +99,14 @@ static inline struct thread_info *current_thread_info(void) /* work to do on interrupt/exception return */ #define _TIF_WORK_MASK \ - ((1 << TIF_SIGPENDING) \ + (_TIF_SIGPENDING \ | _TIF_NOTIFY_RESUME \ - | (1 << TIF_NEED_RESCHED) \ - | (1 << TIF_POLLING_NRFLAG) \ - | (1 << TIF_BREAKPOINT) \ - | (1 << TIF_RESTORE_SIGMASK)) + | _TIF_NEED_RESCHED \ + | _TIF_BREAKPOINT) /* work to do on any return to userspace */ -#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \ - _TIF_NOTIFY_RESUME) +#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | _TIF_SYSCALL_TRACE) /* work to do on return from debug mode */ -#define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT)) +#define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~_TIF_BREAKPOINT) #endif /* __ASM_AVR32_THREAD_INFO_H */ diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index 92c5af98a6f7..1bb0a8abd79b 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -388,14 +388,14 @@ asmlinkage int sys_execve(const char __user *ufilename, struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname(ufilename); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, uargv, uenvp, regs); + error = do_execve(filename->name, uargv, uenvp, regs); putname(filename); out: diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index d552a854dacc..5e01c3a40ced 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -15,7 +15,6 @@ #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/unistd.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/uaccess.h> diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h index 53ad10005ae3..3894005337ba 100644 --- a/arch/blackfin/include/asm/thread_info.h +++ b/arch/blackfin/include/asm/thread_info.h @@ -96,8 +96,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling - 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_IRQ_SYNC 7 /* sync pipeline stage */ @@ -108,8 +106,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_IRQ_SYNC (1<<TIF_IRQ_SYNC) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 62bcea7dcc6d..bb1cc721fcf7 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -213,14 +213,14 @@ asmlinkage int sys_execve(const char __user *name, const char __user *const __user *envp) { int error; - char *filename; + struct filename *filename; struct pt_regs *regs = (struct pt_regs *)((&name) + 6); filename = getname(name); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); return error; } diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index 6682b73a8523..6ed20a1a4af9 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -10,7 +10,6 @@ #include <linux/tty.h> #include <linux/personality.h> #include <linux/binfmts.h> -#include <linux/freezer.h> #include <linux/uaccess.h> #include <linux/tracehook.h> diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index 983c859e40b7..45268b50c0c8 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig @@ -17,6 +17,7 @@ config C6X select OF select OF_EARLY_FLATTREE select GENERIC_CLOCKEVENTS + select GENERIC_KERNEL_THREAD config MMU def_bool n diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h index c50af7ef1c96..b9eb3da7f278 100644 --- a/arch/c6x/include/asm/processor.h +++ b/arch/c6x/include/asm/processor.h @@ -92,8 +92,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - #define copy_segments(tsk, mm) do { } while (0) #define release_segments(mm) do { } while (0) diff --git a/arch/c6x/include/asm/syscalls.h b/arch/c6x/include/asm/syscalls.h index aed53da703c9..e7b8991dc07c 100644 --- a/arch/c6x/include/asm/syscalls.h +++ b/arch/c6x/include/asm/syscalls.h @@ -44,11 +44,6 @@ extern int sys_cache_sync(unsigned long s, unsigned long e); struct pt_regs; extern asmlinkage long sys_c6x_clone(struct pt_regs *regs); -extern asmlinkage long sys_c6x_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp, - struct pt_regs *regs); - #include <asm-generic/syscalls.h> diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h index 1710bcbb8d09..4c8dc562bd90 100644 --- a/arch/c6x/include/asm/thread_info.h +++ b/arch/c6x/include/asm/thread_info.h @@ -97,7 +97,6 @@ struct thread_info *current_thread_info(void) #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */ -#define TIF_POLLING_NRFLAG 16 /* true if polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 17 /* OOM killer killed process */ #define TIF_WORK_MASK 0x00007FFE /* work on irq/exception return */ diff --git a/arch/c6x/include/asm/unistd.h b/arch/c6x/include/asm/unistd.h index ed2259043eec..4ff747d12dad 100644 --- a/arch/c6x/include/asm/unistd.h +++ b/arch/c6x/include/asm/unistd.h @@ -14,6 +14,9 @@ * more details. */ +#define __ARCH_WANT_KERNEL_EXECVE +#define __ARCH_WANT_SYS_EXECVE + /* Use the standard ABI for syscalls. */ #include <asm-generic/unistd.h> diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c index 759ad6d207b6..60f1e437745d 100644 --- a/arch/c6x/kernel/asm-offsets.c +++ b/arch/c6x/kernel/asm-offsets.c @@ -116,7 +116,6 @@ void foo(void) DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME)); DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING)); DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED)); - DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG)); DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK); DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK); diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S index 30b37e5f4a61..5449c36018fe 100644 --- a/arch/c6x/kernel/entry.S +++ b/arch/c6x/kernel/entry.S @@ -400,6 +400,32 @@ ret_from_fork_2: STW .D2T2 B0,*+SP(REGS_A4+8) ENDPROC(ret_from_fork) +ENTRY(ret_from_kernel_thread) +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 schedule_tail,A0 + MVKH .S1 schedule_tail,A0 + B .S2X A0 +#else + B .S2 schedule_tail +#endif + LDW .D2T2 *+SP(REGS_A0+8),B10 /* get fn */ + ADDKPC .S2 0f,B3,3 +0: + B .S2 B10 /* call fn */ + LDW .D2T1 *+SP(REGS_A1+8),A4 /* get arg */ + MVKL .S2 sys_exit,B11 + MVKH .S2 sys_exit,B11 + ADDKPC .S2 0f,B3,1 +0: + BNOP .S2 B11,5 /* jump to sys_exit */ +ENDPROC(ret_from_kernel_thread) + +ENTRY(ret_from_kernel_execve) + GET_THREAD_INFO A12 + BNOP .S2 syscall_exit,4 + ADD .D2X A4,-8,SP +ENDPROC(ret_from_kernel_execve) + ;; ;; These are the interrupt handlers, responsible for calling __do_IRQ() ;; int6 is used for syscalls (see _system_call entry) @@ -593,13 +619,6 @@ ENTRY(sys_sigaltstack) NOP 4 ENDPROC(sys_sigaltstack) - ;; kernel_execve -ENTRY(kernel_execve) - MVK .S2 __NR_execve,B0 - SWE - BNOP .S2 B3,5 -ENDPROC(kernel_execve) - ;; ;; Special system calls ;; return address is in B3 @@ -628,29 +647,6 @@ ENTRY(sys_rt_sigreturn) #endif ENDPROC(sys_rt_sigreturn) -ENTRY(sys_execve) - ADDAW .D2 SP,2,B6 ; put regs addr in 4th parameter - ; & adjust regs stack addr - LDW .D2T2 *+SP(REGS_B4+8),B4 - - ;; c6x_execve(char *name, char **argv, - ;; char **envp, struct pt_regs *regs) -#ifdef CONFIG_C6X_BIG_KERNEL - || MVKL .S1 sys_c6x_execve,A0 - MVKH .S1 sys_c6x_execve,A0 - B .S2X A0 -#else - || B .S2 sys_c6x_execve -#endif - STW .D2T2 B3,*SP--[2] - ADDKPC .S2 ret_from_c6x_execve,B3,3 - -ret_from_c6x_execve: - LDW .D2T2 *++SP[2],B3 - NOP 4 - BNOP .S2 B3,5 -ENDPROC(sys_execve) - ENTRY(sys_pread_c6x) MV .D2X A8,B7 #ifdef CONFIG_C6X_BIG_KERNEL diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c index 45e924a636a0..2770d9a9a84e 100644 --- a/arch/c6x/kernel/process.c +++ b/arch/c6x/kernel/process.c @@ -25,6 +25,7 @@ void (*c6x_restart)(void); void (*c6x_halt)(void); extern asmlinkage void ret_from_fork(void); +extern asmlinkage void ret_from_kernel_thread(void); /* * power off function, if any @@ -103,37 +104,6 @@ void machine_power_off(void) halt_loop(); } -static void kernel_thread_helper(int dummy, void *arg, int (*fn)(void *)) -{ - do_exit(fn(arg)); -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - struct pt_regs regs; - - /* - * copy_thread sets a4 to zero (child return from fork) - * so we can't just set things up to directly return to - * fn. - */ - memset(®s, 0, sizeof(regs)); - regs.b4 = (unsigned long) arg; - regs.a6 = (unsigned long) fn; - regs.pc = (unsigned long) kernel_thread_helper; - local_save_flags(regs.csr); - regs.csr |= 1; - regs.tsr = 5; /* Set GEE and GIE in TSR */ - - /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -1, ®s, - 0, NULL, NULL); -} -EXPORT_SYMBOL(kernel_thread); - void flush_thread(void) { } @@ -191,22 +161,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childregs = task_pt_regs(p); - *childregs = *regs; - childregs->a4 = 0; - - if (usp == -1) + if (!regs) { /* case of __kernel_thread: we return to supervisor space */ + memset(childregs, 0, sizeof(struct pt_regs)); childregs->sp = (unsigned long)(childregs + 1); - else + p->thread.pc = (unsigned long) ret_from_kernel_thread; + childregs->a0 = usp; /* function */ + childregs->a1 = ustk_size; /* argument */ + } else { /* Otherwise use the given stack */ + *childregs = *regs; childregs->sp = usp; + p->thread.pc = (unsigned long) ret_from_fork; + } /* Set usp/ksp */ p->thread.usp = childregs->sp; - /* switch_to uses stack to save/restore 14 callee-saved regs */ thread_saved_ksp(p) = (unsigned long)childregs - 8; - p->thread.pc = (unsigned int) ret_from_fork; - p->thread.wchan = (unsigned long) ret_from_fork; + p->thread.wchan = p->thread.pc; #ifdef __DSBT__ { unsigned long dp; @@ -221,28 +193,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } -/* - * c6x_execve() executes a new program. - */ -SYSCALL_DEFINE4(c6x_execve, const char __user *, name, - const char __user *const __user *, argv, - const char __user *const __user *, envp, - struct pt_regs *, regs) -{ - int error; - char *filename; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - - error = do_execve(filename, argv, envp, regs); - putname(filename); -out: - return error; -} - unsigned long get_wchan(struct task_struct *p) { return p->thread.wchan; diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index bee8df43c201..15ac7150371f 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -212,14 +212,14 @@ asmlinkage int sys_execve(const char *fname, struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname(fname); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); out: return error; diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 0570e8ce603d..4e9992246359 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -224,7 +224,7 @@ sys_execve(const char *fname, struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname(fname); error = PTR_ERR(filename); @@ -232,7 +232,7 @@ sys_execve(const char *fname, if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); out: return error; diff --git a/arch/cris/include/asm/thread_info.h b/arch/cris/include/asm/thread_info.h index 5b1c448df5c0..07c8c40c52b3 100644 --- a/arch/cris/include/asm/thread_info.h +++ b/arch/cris/include/asm/thread_info.h @@ -78,15 +78,12 @@ struct thread_info { #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ -#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) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #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 */ diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 9d262645f667..b7412504f08a 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -12,6 +12,7 @@ config FRV select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_CPU_DEVICES select ARCH_WANT_IPC_PARSE_VERSION + select GENERIC_KERNEL_THREAD config ZONE_DMA bool diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h index dccb9d162318..a34f309e5801 100644 --- a/arch/frv/include/asm/processor.h +++ b/arch/frv/include/asm/processor.h @@ -92,14 +92,12 @@ extern struct task_struct *__kernel_current_task; /* * do necessary setup to start up a newly executed thread. - * - need to discard the frame stacked by init() invoking the execve syscall */ #define start_thread(_regs, _pc, _usp) \ do { \ - __frame = __kernel_frame0_ptr; \ - __frame->pc = (_pc); \ - __frame->psr &= ~PSR_S; \ - __frame->sp = (_usp); \ + _regs->pc = (_pc); \ + _regs->psr &= ~PSR_S; \ + _regs->sp = (_usp); \ } while(0) /* Free all resources held by a thread. */ @@ -107,7 +105,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -extern asmlinkage int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern asmlinkage void save_user_regs(struct user_context *target); extern asmlinkage void *restore_user_regs(const struct user_context *target, ...); diff --git a/arch/frv/include/asm/ptrace.h b/arch/frv/include/asm/ptrace.h index ef6635ca4ecb..bd534b2d0258 100644 --- a/arch/frv/include/asm/ptrace.h +++ b/arch/frv/include/asm/ptrace.h @@ -76,6 +76,7 @@ register struct pt_regs *__frame asm("gr28"); #define user_mode(regs) (!((regs)->psr & PSR_S)) #define instruction_pointer(regs) ((regs)->pc) #define user_stack_pointer(regs) ((regs)->sp) +#define current_pt_regs() (__frame) extern unsigned long user_stack(const struct pt_regs *); #define profile_pc(regs) ((regs)->pc) diff --git a/arch/frv/include/asm/thread_info.h b/arch/frv/include/asm/thread_info.h index 0ff03a33c81e..bebd7eadc772 100644 --- a/arch/frv/include/asm/thread_info.h +++ b/arch/frv/include/asm/thread_info.h @@ -94,7 +94,6 @@ 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_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) @@ -102,8 +101,6 @@ register struct thread_info *__current_thread_info asm("gr15"); #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) -#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 \ diff --git a/arch/frv/include/asm/unistd.h b/arch/frv/include/asm/unistd.h index 67f23a311db6..b6b07e55e473 100644 --- a/arch/frv/include/asm/unistd.h +++ b/arch/frv/include/asm/unistd.h @@ -372,6 +372,8 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_EXECVE +#define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile index ad4087b69968..3cbb3294b9f9 100644 --- a/arch/frv/kernel/Makefile +++ b/arch/frv/kernel/Makefile @@ -7,8 +7,8 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o extra-y:= head.o vmlinux.lds -obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ - kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \ +obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o \ + process.o traps.o ptrace.o signal.o dma.o \ sys_frv.o time.o setup.o frv_ksyms.o \ debug-stub.o irq.o sleep.o uaccess.o diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index 7d5e000fd32e..002732960315 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -863,6 +863,19 @@ ret_from_fork: setlos.p #0,gr8 bra __syscall_exit + .globl ret_from_kernel_thread +ret_from_kernel_thread: + lddi.p @(gr28,#REG_GR(8)),gr20 + call schedule_tail + or.p gr20,gr20,gr8 + calll @(gr21,gr0) + bra sys_exit + + .globl ret_from_kernel_execve +ret_from_kernel_execve: + ori gr28,0,sp + bra __syscall_exit + ################################################################################################### # # Return to user mode is not as complex as all this looks, diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index a89803b58b9a..86c516d96dcd 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -30,7 +30,6 @@ EXPORT_SYMBOL(ip_fast_csum); EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); #endif -EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(__res_bus_clock_speed_HZ); EXPORT_SYMBOL(__page_offset); diff --git a/arch/frv/kernel/kernel_execve.S b/arch/frv/kernel/kernel_execve.S deleted file mode 100644 index 9b074a16a052..000000000000 --- a/arch/frv/kernel/kernel_execve.S +++ /dev/null @@ -1,33 +0,0 @@ -/* in-kernel program execution - * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/linkage.h> -#include <asm/unistd.h> - -############################################################################### -# -# Do a system call from kernel instead of calling sys_execve so we end up with -# proper pt_regs. -# -# int kernel_execve(const char *filename, char *const argv[], char *const envp[]) -# -# On entry: GR8/GR9/GR10: arguments to function -# On return: GR8: syscall return. -# -############################################################################### - .globl kernel_execve - .type kernel_execve,@function -kernel_execve: - setlos __NR_execve,gr7 - tira gr0,#0 - bralr - - .size kernel_execve,.-kernel_execve diff --git a/arch/frv/kernel/kernel_thread.S b/arch/frv/kernel/kernel_thread.S deleted file mode 100644 index f0e52943f923..000000000000 --- a/arch/frv/kernel/kernel_thread.S +++ /dev/null @@ -1,77 +0,0 @@ -/* kernel_thread.S: kernel thread creation - * - * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/linkage.h> -#include <linux/kern_levels.h> -#include <asm/unistd.h> - -#define CLONE_VM 0x00000100 /* set if VM shared between processes */ - - .section .rodata -kernel_thread_emsg: - .asciz KERN_ERR "failed to create kernel thread: error=%d\n" - - .text - .balign 4 - -############################################################################### -# -# Create a kernel thread -# -# int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -# -############################################################################### - .globl kernel_thread - .type kernel_thread,@function -kernel_thread: - or.p gr8,gr0,gr4 - or gr9,gr0,gr5 - - # start by forking the current process, but with shared VM - setlos.p #__NR_clone,gr7 ; syscall number - ori gr10,#CLONE_VM,gr8 ; first syscall arg [clone_flags] - sethi.p #0xe4e4,gr9 ; second syscall arg [newsp] - setlo #0xe4e4,gr9 - setlos.p #0,gr10 ; third syscall arg [parent_tidptr] - setlos #0,gr11 ; fourth syscall arg [child_tidptr] - tira gr0,#0 - setlos.p #4095,gr7 - andcc gr8,gr8,gr0,icc0 - addcc.p gr8,gr7,gr0,icc1 - bnelr icc0,#2 - bc icc1,#0,kernel_thread_error - - # now invoke the work function - or gr5,gr0,gr8 - calll @(gr4,gr0) - - # and finally exit the thread - setlos #__NR_exit,gr7 ; syscall number - tira gr0,#0 - -kernel_thread_error: - subi sp,#8,sp - movsg lr,gr4 - sti gr8,@(sp,#0) - sti.p gr4,@(sp,#4) - - or gr8,gr0,gr9 - sethi.p %hi(kernel_thread_emsg),gr8 - setlo %lo(kernel_thread_emsg),gr8 - - call printk - - ldi @(sp,#4),gr4 - ldi @(sp,#0),gr8 - subi sp,#8,sp - jmpl @(gr4,gr0) - - .size kernel_thread,.-kernel_thread diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 2eb7fa5bf9d8..655d90d20bb0 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -38,6 +38,7 @@ #include "local.h" asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); #include <asm/pgalloc.h> @@ -172,32 +173,13 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, * set up the kernel stack and exception frames for a new process */ int copy_thread(unsigned long clone_flags, - unsigned long usp, unsigned long topstk, + unsigned long usp, unsigned long arg, struct task_struct *p, struct pt_regs *regs) { - struct pt_regs *childregs0, *childregs, *regs0; + struct pt_regs *childregs; - regs0 = __kernel_frame0_ptr; - childregs0 = (struct pt_regs *) + childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE); - childregs = childregs0; - - /* set up the userspace frame (the only place that the USP is stored) */ - *childregs0 = *regs0; - - childregs0->gr8 = 0; - childregs0->sp = usp; - childregs0->next_frame = NULL; - - /* set up the return kernel frame if called from kernel_thread() */ - if (regs != regs0) { - childregs--; - *childregs = *regs; - childregs->sp = (unsigned long) childregs0; - childregs->next_frame = childregs0; - childregs->gr15 = (unsigned long) task_thread_info(p); - childregs->gr29 = (unsigned long) p; - } p->set_child_tid = p->clear_child_tid = NULL; @@ -206,8 +188,25 @@ int copy_thread(unsigned long clone_flags, p->thread.sp = (unsigned long) childregs; p->thread.fp = 0; p->thread.lr = 0; - p->thread.pc = (unsigned long) ret_from_fork; - p->thread.frame0 = childregs0; + p->thread.frame0 = childregs; + + if (unlikely(!regs)) { + memset(childregs, 0, sizeof(struct pt_regs)); + childregs->gr9 = usp; /* function */ + childregs->gr8 = arg; + chilregs->psr = PSR_S; + p->thread.pc = (unsigned long) ret_from_kernel_thread; + save_user_regs(p->thread.user); + return 0; + } + + /* set up the userspace frame (the only place that the USP is stored) */ + *childregs = *regs; + + childregs->sp = usp; + childregs->next_frame = NULL; + + p->thread.pc = (unsigned long) ret_from_fork; /* the new TLS pointer is passed in as arg #5 to sys_clone() */ if (clone_flags & CLONE_SETTLS) @@ -218,25 +217,6 @@ int copy_thread(unsigned long clone_flags, return 0; } /* end copy_thread() */ -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - int error; - char * filename; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, __frame); - putname(filename); - return error; -} - unsigned long get_wchan(struct task_struct *p) { struct pt_regs *regs0; diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 864c2f0d497b..535810a3217a 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -20,7 +20,6 @@ #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/personality.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/ucontext.h> #include <asm/uaccess.h> @@ -298,10 +297,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) __frame->lr = (unsigned long) &frame->retcode; __frame->gr8 = sig; - /* the tracer may want to single-step inside the handler */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - #if DEBUG_SIG printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", sig, current->comm, current->pid, frame, __frame->pc, @@ -400,10 +395,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, __frame->gr8 = sig; __frame->gr9 = (unsigned long) &frame->info; - /* the tracer may want to single-step inside the handler */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - #if DEBUG_SIG printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", sig, current->comm, current->pid, frame, __frame->pc, diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h index 9c126e0c09aa..ec2f7777c65a 100644 --- a/arch/h8300/include/asm/thread_info.h +++ b/arch/h8300/include/asm/thread_info.h @@ -85,8 +85,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling - 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_NOTIFY_RESUME 6 /* callback before returning to user */ @@ -95,11 +93,10 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) -#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ +#define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ + _TIF_NOTIFY_RESUME) #endif /* __KERNEL__ */ diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index f153ed1a4c08..e8dc1393a13a 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -217,14 +217,14 @@ asmlinkage int sys_execve(const char *name, int dummy, ...) { int error; - char * filename; + struct filename *filename; struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4); filename = getname(name); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); return error; } diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 5adaadaf9218..0e81b96c642f 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -38,7 +38,6 @@ #include <linux/personality.h> #include <linux/tty.h> #include <linux/binfmts.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/setup.h> diff --git a/arch/hexagon/include/asm/thread_info.h b/arch/hexagon/include/asm/thread_info.h index 4f936a7ee847..e4a0aad69cbb 100644 --- a/arch/hexagon/include/asm/thread_info.h +++ b/arch/hexagon/include/asm/thread_info.h @@ -120,10 +120,8 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG); #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore ss @ return to usr mode */ -#define TIF_IRET 5 /* return with iret */ #define TIF_RESTORE_SIGMASK 6 /* restore sig mask in do_signal() */ /* true if poll_idle() is polling TIF_NEED_RESCHED */ -#define TIF_POLLING_NRFLAG 16 #define TIF_MEMDIE 17 /* OOM killer killed process */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) @@ -131,9 +129,6 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG); #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) -#define _TIF_IRET (1 << TIF_IRET) -#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) -#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) /* work to do on interrupt/exception return - All but TIF_SYSCALL_TRACE */ #define _TIF_WORK_MASK (0x0000FFFF & ~_TIF_SYSCALL_TRACE) diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index 304b0808d072..1ea16bec7b91 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c @@ -20,7 +20,6 @@ #include <linux/linkage.h> #include <linux/syscalls.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/registers.h> #include <asm/thread_info.h> diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c index 553cd60ee659..25a9bfe3445d 100644 --- a/arch/hexagon/kernel/syscall.c +++ b/arch/hexagon/kernel/syscall.c @@ -40,7 +40,7 @@ asmlinkage int sys_execve(char __user *ufilename, const char __user *const __user *envp) { struct pt_regs *pregs = current_thread_info()->regs; - char *filename; + struct filename *filename; int retval; filename = getname(ufilename); @@ -48,7 +48,7 @@ asmlinkage int sys_execve(char __user *ufilename, if (IS_ERR(filename)) return retval; - retval = do_execve(filename, argv, envp, pregs); + retval = do_execve(filename->name, argv, envp, pregs); putname(filename); return retval; diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3c720ef6c32d..4c10e607c908 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -39,7 +39,7 @@ config IA64 select ARCH_TASK_STRUCT_ALLOCATOR select ARCH_THREAD_INFO_ALLOCATOR select ARCH_CLOCKSOURCE_DATA - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL_OLD default y help The Itanium Processor Family is Intel's 64-bit successor to diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild index 562f59315847..4a159da23633 100644 --- a/arch/ia64/include/asm/Kbuild +++ b/arch/ia64/include/asm/Kbuild @@ -1,17 +1,3 @@ -include include/asm-generic/Kbuild.asm -header-y += break.h -header-y += cmpxchg.h -header-y += fpu.h -header-y += gcc_intrin.h -header-y += ia64regs.h -header-y += intel_intrin.h -header-y += intrinsics.h -header-y += perfmon.h -header-y += perfmon_default_smpl.h -header-y += ptrace_offsets.h -header-y += rse.h -header-y += ucontext.h -header-y += ustack.h generic-y += clkdev.h generic-y += exec.h diff --git a/arch/ia64/include/asm/gcc_intrin.h b/arch/ia64/include/asm/gcc_intrin.h index 21ddee54adae..f9495b1757a8 100644 --- a/arch/ia64/include/asm/gcc_intrin.h +++ b/arch/ia64/include/asm/gcc_intrin.h @@ -1,621 +1,12 @@ -#ifndef _ASM_IA64_GCC_INTRIN_H -#define _ASM_IA64_GCC_INTRIN_H /* * * Copyright (C) 2002,2003 Jun Nakajima <jun.nakajima@intel.com> * Copyright (C) 2002,2003 Suresh Siddha <suresh.b.siddha@intel.com> */ +#ifndef _ASM_IA64_GCC_INTRIN_H +#define _ASM_IA64_GCC_INTRIN_H -#include <linux/types.h> -#include <linux/compiler.h> - -/* define this macro to get some asm stmts included in 'c' files */ -#define ASM_SUPPORTED - -/* Optimization barrier */ -/* The "volatile" is due to gcc bugs */ -#define ia64_barrier() asm volatile ("":::"memory") - -#define ia64_stop() asm volatile (";;"::) - -#define ia64_invala_gr(regnum) asm volatile ("invala.e r%0" :: "i"(regnum)) - -#define ia64_invala_fr(regnum) asm volatile ("invala.e f%0" :: "i"(regnum)) - -#define ia64_flushrs() asm volatile ("flushrs;;":::"memory") - -#define ia64_loadrs() asm volatile ("loadrs;;":::"memory") - -extern void ia64_bad_param_for_setreg (void); -extern void ia64_bad_param_for_getreg (void); +#include <uapi/asm/gcc_intrin.h> -#ifdef __KERNEL__ register unsigned long ia64_r13 asm ("r13") __used; -#endif - -#define ia64_native_setreg(regnum, val) \ -({ \ - switch (regnum) { \ - case _IA64_REG_PSR_L: \ - asm volatile ("mov psr.l=%0" :: "r"(val) : "memory"); \ - break; \ - case _IA64_REG_AR_KR0 ... _IA64_REG_AR_EC: \ - asm volatile ("mov ar%0=%1" :: \ - "i" (regnum - _IA64_REG_AR_KR0), \ - "r"(val): "memory"); \ - break; \ - case _IA64_REG_CR_DCR ... _IA64_REG_CR_LRR1: \ - asm volatile ("mov cr%0=%1" :: \ - "i" (regnum - _IA64_REG_CR_DCR), \ - "r"(val): "memory" ); \ - break; \ - case _IA64_REG_SP: \ - asm volatile ("mov r12=%0" :: \ - "r"(val): "memory"); \ - break; \ - case _IA64_REG_GP: \ - asm volatile ("mov gp=%0" :: "r"(val) : "memory"); \ - break; \ - default: \ - ia64_bad_param_for_setreg(); \ - break; \ - } \ -}) - -#define ia64_native_getreg(regnum) \ -({ \ - __u64 ia64_intri_res; \ - \ - switch (regnum) { \ - case _IA64_REG_GP: \ - asm volatile ("mov %0=gp" : "=r"(ia64_intri_res)); \ - break; \ - case _IA64_REG_IP: \ - asm volatile ("mov %0=ip" : "=r"(ia64_intri_res)); \ - break; \ - case _IA64_REG_PSR: \ - asm volatile ("mov %0=psr" : "=r"(ia64_intri_res)); \ - break; \ - case _IA64_REG_TP: /* for current() */ \ - ia64_intri_res = ia64_r13; \ - break; \ - case _IA64_REG_AR_KR0 ... _IA64_REG_AR_EC: \ - asm volatile ("mov %0=ar%1" : "=r" (ia64_intri_res) \ - : "i"(regnum - _IA64_REG_AR_KR0)); \ - break; \ - case _IA64_REG_CR_DCR ... _IA64_REG_CR_LRR1: \ - asm volatile ("mov %0=cr%1" : "=r" (ia64_intri_res) \ - : "i" (regnum - _IA64_REG_CR_DCR)); \ - break; \ - case _IA64_REG_SP: \ - asm volatile ("mov %0=sp" : "=r" (ia64_intri_res)); \ - break; \ - default: \ - ia64_bad_param_for_getreg(); \ - break; \ - } \ - ia64_intri_res; \ -}) - -#define ia64_hint_pause 0 - -#define ia64_hint(mode) \ -({ \ - switch (mode) { \ - case ia64_hint_pause: \ - asm volatile ("hint @pause" ::: "memory"); \ - break; \ - } \ -}) - - -/* Integer values for mux1 instruction */ -#define ia64_mux1_brcst 0 -#define ia64_mux1_mix 8 -#define ia64_mux1_shuf 9 -#define ia64_mux1_alt 10 -#define ia64_mux1_rev 11 - -#define ia64_mux1(x, mode) \ -({ \ - __u64 ia64_intri_res; \ - \ - switch (mode) { \ - case ia64_mux1_brcst: \ - asm ("mux1 %0=%1,@brcst" : "=r" (ia64_intri_res) : "r" (x)); \ - break; \ - case ia64_mux1_mix: \ - asm ("mux1 %0=%1,@mix" : "=r" (ia64_intri_res) : "r" (x)); \ - break; \ - case ia64_mux1_shuf: \ - asm ("mux1 %0=%1,@shuf" : "=r" (ia64_intri_res) : "r" (x)); \ - break; \ - case ia64_mux1_alt: \ - asm ("mux1 %0=%1,@alt" : "=r" (ia64_intri_res) : "r" (x)); \ - break; \ - case ia64_mux1_rev: \ - asm ("mux1 %0=%1,@rev" : "=r" (ia64_intri_res) : "r" (x)); \ - break; \ - } \ - ia64_intri_res; \ -}) - -#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# define ia64_popcnt(x) __builtin_popcountl(x) -#else -# define ia64_popcnt(x) \ - ({ \ - __u64 ia64_intri_res; \ - asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \ - \ - ia64_intri_res; \ - }) -#endif - -#define ia64_getf_exp(x) \ -({ \ - long ia64_intri_res; \ - \ - asm ("getf.exp %0=%1" : "=r"(ia64_intri_res) : "f"(x)); \ - \ - ia64_intri_res; \ -}) - -#define ia64_shrp(a, b, count) \ -({ \ - __u64 ia64_intri_res; \ - asm ("shrp %0=%1,%2,%3" : "=r"(ia64_intri_res) : "r"(a), "r"(b), "i"(count)); \ - ia64_intri_res; \ -}) - -#define ia64_ldfs(regnum, x) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("ldfs %0=[%1]" :"=f"(__f__): "r"(x)); \ -}) - -#define ia64_ldfd(regnum, x) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("ldfd %0=[%1]" :"=f"(__f__): "r"(x)); \ -}) - -#define ia64_ldfe(regnum, x) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("ldfe %0=[%1]" :"=f"(__f__): "r"(x)); \ -}) - -#define ia64_ldf8(regnum, x) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("ldf8 %0=[%1]" :"=f"(__f__): "r"(x)); \ -}) - -#define ia64_ldf_fill(regnum, x) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("ldf.fill %0=[%1]" :"=f"(__f__): "r"(x)); \ -}) - -#define ia64_st4_rel_nta(m, val) \ -({ \ - asm volatile ("st4.rel.nta [%0] = %1\n\t" :: "r"(m), "r"(val)); \ -}) - -#define ia64_stfs(x, regnum) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("stfs [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ -}) - -#define ia64_stfd(x, regnum) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("stfd [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ -}) - -#define ia64_stfe(x, regnum) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ -}) - -#define ia64_stf8(x, regnum) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ -}) - -#define ia64_stf_spill(x, regnum) \ -({ \ - register double __f__ asm ("f"#regnum); \ - asm volatile ("stf.spill [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ -}) - -#define ia64_fetchadd4_acq(p, inc) \ -({ \ - \ - __u64 ia64_intri_res; \ - asm volatile ("fetchadd4.acq %0=[%1],%2" \ - : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ - : "memory"); \ - \ - ia64_intri_res; \ -}) - -#define ia64_fetchadd4_rel(p, inc) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("fetchadd4.rel %0=[%1],%2" \ - : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ - : "memory"); \ - \ - ia64_intri_res; \ -}) - -#define ia64_fetchadd8_acq(p, inc) \ -({ \ - \ - __u64 ia64_intri_res; \ - asm volatile ("fetchadd8.acq %0=[%1],%2" \ - : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ - : "memory"); \ - \ - ia64_intri_res; \ -}) - -#define ia64_fetchadd8_rel(p, inc) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("fetchadd8.rel %0=[%1],%2" \ - : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ - : "memory"); \ - \ - ia64_intri_res; \ -}) - -#define ia64_xchg1(ptr,x) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("xchg1 %0=[%1],%2" \ - : "=r" (ia64_intri_res) : "r" (ptr), "r" (x) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_xchg2(ptr,x) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("xchg2 %0=[%1],%2" : "=r" (ia64_intri_res) \ - : "r" (ptr), "r" (x) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_xchg4(ptr,x) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("xchg4 %0=[%1],%2" : "=r" (ia64_intri_res) \ - : "r" (ptr), "r" (x) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_xchg8(ptr,x) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("xchg8 %0=[%1],%2" : "=r" (ia64_intri_res) \ - : "r" (ptr), "r" (x) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg1_acq(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - asm volatile ("cmpxchg1.acq %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg1_rel(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - asm volatile ("cmpxchg1.rel %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg2_acq(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - asm volatile ("cmpxchg2.acq %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg2_rel(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - \ - asm volatile ("cmpxchg2.rel %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg4_acq(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - asm volatile ("cmpxchg4.acq %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg4_rel(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - asm volatile ("cmpxchg4.rel %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg8_acq(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - asm volatile ("cmpxchg8.acq %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_cmpxchg8_rel(ptr, new, old) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ - \ - asm volatile ("cmpxchg8.rel %0=[%1],%2,ar.ccv": \ - "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ - ia64_intri_res; \ -}) - -#define ia64_mf() asm volatile ("mf" ::: "memory") -#define ia64_mfa() asm volatile ("mf.a" ::: "memory") - -#define ia64_invala() asm volatile ("invala" ::: "memory") - -#define ia64_native_thash(addr) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("thash %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \ - ia64_intri_res; \ -}) - -#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory") -#define ia64_srlz_d() asm volatile (";; srlz.d" ::: "memory"); - -#ifdef HAVE_SERIALIZE_DIRECTIVE -# define ia64_dv_serialize_data() asm volatile (".serialize.data"); -# define ia64_dv_serialize_instruction() asm volatile (".serialize.instruction"); -#else -# define ia64_dv_serialize_data() -# define ia64_dv_serialize_instruction() -#endif - -#define ia64_nop(x) asm volatile ("nop %0"::"i"(x)); - -#define ia64_itci(addr) asm volatile ("itc.i %0;;" :: "r"(addr) : "memory") - -#define ia64_itcd(addr) asm volatile ("itc.d %0;;" :: "r"(addr) : "memory") - - -#define ia64_itri(trnum, addr) asm volatile ("itr.i itr[%0]=%1" \ - :: "r"(trnum), "r"(addr) : "memory") - -#define ia64_itrd(trnum, addr) asm volatile ("itr.d dtr[%0]=%1" \ - :: "r"(trnum), "r"(addr) : "memory") - -#define ia64_tpa(addr) \ -({ \ - unsigned long ia64_pa; \ - asm volatile ("tpa %0 = %1" : "=r"(ia64_pa) : "r"(addr) : "memory"); \ - ia64_pa; \ -}) - -#define __ia64_set_dbr(index, val) \ - asm volatile ("mov dbr[%0]=%1" :: "r"(index), "r"(val) : "memory") - -#define ia64_set_ibr(index, val) \ - asm volatile ("mov ibr[%0]=%1" :: "r"(index), "r"(val) : "memory") - -#define ia64_set_pkr(index, val) \ - asm volatile ("mov pkr[%0]=%1" :: "r"(index), "r"(val) : "memory") - -#define ia64_set_pmc(index, val) \ - asm volatile ("mov pmc[%0]=%1" :: "r"(index), "r"(val) : "memory") - -#define ia64_set_pmd(index, val) \ - asm volatile ("mov pmd[%0]=%1" :: "r"(index), "r"(val) : "memory") - -#define ia64_native_set_rr(index, val) \ - asm volatile ("mov rr[%0]=%1" :: "r"(index), "r"(val) : "memory"); - -#define ia64_native_get_cpuid(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=cpuid[%r1]" : "=r"(ia64_intri_res) : "rO"(index)); \ - ia64_intri_res; \ -}) - -#define __ia64_get_dbr(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=dbr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ - ia64_intri_res; \ -}) - -#define ia64_get_ibr(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=ibr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ - ia64_intri_res; \ -}) - -#define ia64_get_pkr(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=pkr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ - ia64_intri_res; \ -}) - -#define ia64_get_pmc(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=pmc[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ - ia64_intri_res; \ -}) - - -#define ia64_native_get_pmd(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=pmd[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ - ia64_intri_res; \ -}) - -#define ia64_native_get_rr(index) \ -({ \ - unsigned long ia64_intri_res; \ - asm volatile ("mov %0=rr[%1]" : "=r"(ia64_intri_res) : "r" (index)); \ - ia64_intri_res; \ -}) - -#define ia64_native_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory") - - -#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory") - -#define ia64_native_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory") -#define ia64_native_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory") -#define ia64_sum(mask) asm volatile ("sum %0":: "i"((mask)) : "memory") -#define ia64_rum(mask) asm volatile ("rum %0":: "i"((mask)) : "memory") - -#define ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr)) - -#define ia64_native_ptcga(addr, size) \ -do { \ - asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory"); \ - ia64_dv_serialize_data(); \ -} while (0) - -#define ia64_ptcl(addr, size) \ -do { \ - asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(size) : "memory"); \ - ia64_dv_serialize_data(); \ -} while (0) - -#define ia64_ptri(addr, size) \ - asm volatile ("ptr.i %0,%1" :: "r"(addr), "r"(size) : "memory") - -#define ia64_ptrd(addr, size) \ - asm volatile ("ptr.d %0,%1" :: "r"(addr), "r"(size) : "memory") - -#define ia64_ttag(addr) \ -({ \ - __u64 ia64_intri_res; \ - asm volatile ("ttag %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \ - ia64_intri_res; \ -}) - - -/* Values for lfhint in ia64_lfetch and ia64_lfetch_fault */ - -#define ia64_lfhint_none 0 -#define ia64_lfhint_nt1 1 -#define ia64_lfhint_nt2 2 -#define ia64_lfhint_nta 3 - -#define ia64_lfetch(lfhint, y) \ -({ \ - switch (lfhint) { \ - case ia64_lfhint_none: \ - asm volatile ("lfetch [%0]" : : "r"(y)); \ - break; \ - case ia64_lfhint_nt1: \ - asm volatile ("lfetch.nt1 [%0]" : : "r"(y)); \ - break; \ - case ia64_lfhint_nt2: \ - asm volatile ("lfetch.nt2 [%0]" : : "r"(y)); \ - break; \ - case ia64_lfhint_nta: \ - asm volatile ("lfetch.nta [%0]" : : "r"(y)); \ - break; \ - } \ -}) - -#define ia64_lfetch_excl(lfhint, y) \ -({ \ - switch (lfhint) { \ - case ia64_lfhint_none: \ - asm volatile ("lfetch.excl [%0]" :: "r"(y)); \ - break; \ - case ia64_lfhint_nt1: \ - asm volatile ("lfetch.excl.nt1 [%0]" :: "r"(y)); \ - break; \ - case ia64_lfhint_nt2: \ - asm volatile ("lfetch.excl.nt2 [%0]" :: "r"(y)); \ - break; \ - case ia64_lfhint_nta: \ - asm volatile ("lfetch.excl.nta [%0]" :: "r"(y)); \ - break; \ - } \ -}) - -#define ia64_lfetch_fault(lfhint, y) \ -({ \ - switch (lfhint) { \ - case ia64_lfhint_none: \ - asm volatile ("lfetch.fault [%0]" : : "r"(y)); \ - break; \ - case ia64_lfhint_nt1: \ - asm volatile ("lfetch.fault.nt1 [%0]" : : "r"(y)); \ - break; \ - case ia64_lfhint_nt2: \ - asm volatile ("lfetch.fault.nt2 [%0]" : : "r"(y)); \ - break; \ - case ia64_lfhint_nta: \ - asm volatile ("lfetch.fault.nta [%0]" : : "r"(y)); \ - break; \ - } \ -}) - -#define ia64_lfetch_fault_excl(lfhint, y) \ -({ \ - switch (lfhint) { \ - case ia64_lfhint_none: \ - asm volatile ("lfetch.fault.excl [%0]" :: "r"(y)); \ - break; \ - case ia64_lfhint_nt1: \ - asm volatile ("lfetch.fault.excl.nt1 [%0]" :: "r"(y)); \ - break; \ - case ia64_lfhint_nt2: \ - asm volatile ("lfetch.fault.excl.nt2 [%0]" :: "r"(y)); \ - break; \ - case ia64_lfhint_nta: \ - asm volatile ("lfetch.fault.excl.nta [%0]" :: "r"(y)); \ - break; \ - } \ -}) - -#define ia64_native_intrin_local_irq_restore(x) \ -do { \ - asm volatile (";; cmp.ne p6,p7=%0,r0;;" \ - "(p6) ssm psr.i;" \ - "(p7) rsm psr.i;;" \ - "(p6) srlz.d" \ - :: "r"((x)) : "p6", "p7", "memory"); \ -} while (0) - #endif /* _ASM_IA64_GCC_INTRIN_H */ diff --git a/arch/ia64/include/asm/intrinsics.h b/arch/ia64/include/asm/intrinsics.h index d129e367e764..20477ea111ba 100644 --- a/arch/ia64/include/asm/intrinsics.h +++ b/arch/ia64/include/asm/intrinsics.h @@ -1,99 +1,16 @@ -#ifndef _ASM_IA64_INTRINSICS_H -#define _ASM_IA64_INTRINSICS_H - /* * Compiler-dependent intrinsics. * * Copyright (C) 2002-2003 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> */ +#ifndef _ASM_IA64_INTRINSICS_H +#define _ASM_IA64_INTRINSICS_H -#ifndef __ASSEMBLY__ - -#include <linux/types.h> -/* include compiler specific intrinsics */ -#include <asm/ia64regs.h> -#ifdef __INTEL_COMPILER -# include <asm/intel_intrin.h> -#else -# include <asm/gcc_intrin.h> -#endif -#include <asm/cmpxchg.h> - -#define ia64_native_get_psr_i() (ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I) - -#define ia64_native_set_rr0_to_rr4(val0, val1, val2, val3, val4) \ -do { \ - ia64_native_set_rr(0x0000000000000000UL, (val0)); \ - ia64_native_set_rr(0x2000000000000000UL, (val1)); \ - ia64_native_set_rr(0x4000000000000000UL, (val2)); \ - ia64_native_set_rr(0x6000000000000000UL, (val3)); \ - ia64_native_set_rr(0x8000000000000000UL, (val4)); \ -} while (0) - -/* - * Force an unresolved reference if someone tries to use - * ia64_fetch_and_add() with a bad value. - */ -extern unsigned long __bad_size_for_ia64_fetch_and_add (void); -extern unsigned long __bad_increment_for_ia64_fetch_and_add (void); - -#define IA64_FETCHADD(tmp,v,n,sz,sem) \ -({ \ - switch (sz) { \ - case 4: \ - tmp = ia64_fetchadd4_##sem((unsigned int *) v, n); \ - break; \ - \ - case 8: \ - tmp = ia64_fetchadd8_##sem((unsigned long *) v, n); \ - break; \ - \ - default: \ - __bad_size_for_ia64_fetch_and_add(); \ - } \ -}) - -#define ia64_fetchadd(i,v,sem) \ -({ \ - __u64 _tmp; \ - volatile __typeof__(*(v)) *_v = (v); \ - /* Can't use a switch () here: gcc isn't always smart enough for that... */ \ - if ((i) == -16) \ - IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v)), sem); \ - else if ((i) == -8) \ - IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v)), sem); \ - else if ((i) == -4) \ - IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v)), sem); \ - else if ((i) == -1) \ - IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v)), sem); \ - else if ((i) == 1) \ - IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v)), sem); \ - else if ((i) == 4) \ - IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v)), sem); \ - else if ((i) == 8) \ - IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v)), sem); \ - else if ((i) == 16) \ - IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v)), sem); \ - else \ - _tmp = __bad_increment_for_ia64_fetch_and_add(); \ - (__typeof__(*(v))) (_tmp); /* return old value */ \ -}) - -#define ia64_fetch_and_add(i,v) (ia64_fetchadd(i, v, rel) + (i)) /* return new value */ - -#endif - -#ifdef __KERNEL__ #include <asm/paravirt_privop.h> -#endif +#include <uapi/asm/intrinsics.h> #ifndef __ASSEMBLY__ - -#define IA64_INTRINSIC_API(name) ia64_native_ ## name -#define IA64_INTRINSIC_MACRO(name) ia64_native_ ## name - -#if defined(__KERNEL__) #if defined(CONFIG_PARAVIRT) # undef IA64_INTRINSIC_API # undef IA64_INTRINSIC_MACRO @@ -104,36 +21,5 @@ extern unsigned long __bad_increment_for_ia64_fetch_and_add (void); # endif #define IA64_INTRINSIC_MACRO(name) paravirt_ ## name #endif -#endif - -/************************************************/ -/* Instructions paravirtualized for correctness */ -/************************************************/ -/* fc, thash, get_cpuid, get_pmd, get_eflags, set_eflags */ -/* Note that "ttag" and "cover" are also privilege-sensitive; "ttag" - * is not currently used (though it may be in a long-format VHPT system!) - */ -#define ia64_fc IA64_INTRINSIC_API(fc) -#define ia64_thash IA64_INTRINSIC_API(thash) -#define ia64_get_cpuid IA64_INTRINSIC_API(get_cpuid) -#define ia64_get_pmd IA64_INTRINSIC_API(get_pmd) - - -/************************************************/ -/* Instructions paravirtualized for performance */ -/************************************************/ -#define ia64_ssm IA64_INTRINSIC_MACRO(ssm) -#define ia64_rsm IA64_INTRINSIC_MACRO(rsm) -#define ia64_getreg IA64_INTRINSIC_MACRO(getreg) -#define ia64_setreg IA64_INTRINSIC_API(setreg) -#define ia64_set_rr IA64_INTRINSIC_API(set_rr) -#define ia64_get_rr IA64_INTRINSIC_API(get_rr) -#define ia64_ptcga IA64_INTRINSIC_API(ptcga) -#define ia64_get_psr_i IA64_INTRINSIC_API(get_psr_i) -#define ia64_intrin_local_irq_restore \ - IA64_INTRINSIC_API(intrin_local_irq_restore) -#define ia64_set_rr0_to_rr4 IA64_INTRINSIC_API(set_rr0_to_rr4) - #endif /* !__ASSEMBLY__ */ - #endif /* _ASM_IA64_INTRINSICS_H */ diff --git a/arch/ia64/include/asm/kvm_para.h b/arch/ia64/include/asm/kvm_para.h index 2019cb99335e..47c00f910434 100644 --- a/arch/ia64/include/asm/kvm_para.h +++ b/arch/ia64/include/asm/kvm_para.h @@ -1,6 +1,3 @@ -#ifndef __IA64_KVM_PARA_H -#define __IA64_KVM_PARA_H - /* * Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com> * @@ -18,8 +15,11 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. * */ +#ifndef __IA64_KVM_PARA_H +#define __IA64_KVM_PARA_H + +#include <uapi/asm/kvm_para.h> -#ifdef __KERNEL__ static inline unsigned int kvm_arch_para_features(void) { @@ -32,5 +32,3 @@ static inline bool kvm_check_and_clear_guest_paused(void) } #endif - -#endif diff --git a/arch/ia64/include/asm/mman.h b/arch/ia64/include/asm/mman.h index 4459028e5aa8..fdd5f5229f78 100644 --- a/arch/ia64/include/asm/mman.h +++ b/arch/ia64/include/asm/mman.h @@ -1,23 +1,17 @@ -#ifndef _ASM_IA64_MMAN_H -#define _ASM_IA64_MMAN_H - /* * Based on <asm-i386/mman.h>. * * Modified 1998-2000, 2002 * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co */ +#ifndef _ASM_IA64_MMAN_H +#define _ASM_IA64_MMAN_H -#include <asm-generic/mman.h> - -#define MAP_GROWSUP 0x0200 /* register stack-like segment */ +#include <uapi/asm/mman.h> -#ifdef __KERNEL__ #ifndef __ASSEMBLY__ #define arch_mmap_check ia64_mmap_check int ia64_mmap_check(unsigned long addr, unsigned long len, unsigned long flags); #endif -#endif - #endif /* _ASM_IA64_MMAN_H */ diff --git a/arch/ia64/include/asm/param.h b/arch/ia64/include/asm/param.h index 0964c32c1358..1295913d6a82 100644 --- a/arch/ia64/include/asm/param.h +++ b/arch/ia64/include/asm/param.h @@ -1,6 +1,3 @@ -#ifndef _ASM_IA64_PARAM_H -#define _ASM_IA64_PARAM_H - /* * Fundamental kernel parameters. * @@ -9,25 +6,12 @@ * Modified 1998, 1999, 2002-2003 * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co */ +#ifndef _ASM_IA64_PARAM_H +#define _ASM_IA64_PARAM_H -#define EXEC_PAGESIZE 65536 - -#ifndef NOGROUP -# define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ +#include <uapi/asm/param.h> -#ifdef __KERNEL__ # define HZ CONFIG_HZ # define USER_HZ HZ # define CLOCKS_PER_SEC HZ /* frequency at which times() counts */ -#else - /* - * Technically, this is wrong, but some old apps still refer to it. The proper way to - * get the HZ value is via sysconf(_SC_CLK_TCK). - */ -# define HZ 1024 -#endif - #endif /* _ASM_IA64_PARAM_H */ diff --git a/arch/ia64/include/asm/perfmon.h b/arch/ia64/include/asm/perfmon.h index d551183fee90..15476dd3a8b0 100644 --- a/arch/ia64/include/asm/perfmon.h +++ b/arch/ia64/include/asm/perfmon.h @@ -2,179 +2,12 @@ * Copyright (C) 2001-2003 Hewlett-Packard Co * Stephane Eranian <eranian@hpl.hp.com> */ - #ifndef _ASM_IA64_PERFMON_H #define _ASM_IA64_PERFMON_H -/* - * perfmon commands supported on all CPU models - */ -#define PFM_WRITE_PMCS 0x01 -#define PFM_WRITE_PMDS 0x02 -#define PFM_READ_PMDS 0x03 -#define PFM_STOP 0x04 -#define PFM_START 0x05 -#define PFM_ENABLE 0x06 /* obsolete */ -#define PFM_DISABLE 0x07 /* obsolete */ -#define PFM_CREATE_CONTEXT 0x08 -#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */ -#define PFM_RESTART 0x0a -#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ -#define PFM_GET_FEATURES 0x0c -#define PFM_DEBUG 0x0d -#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ -#define PFM_GET_PMC_RESET_VAL 0x0f -#define PFM_LOAD_CONTEXT 0x10 -#define PFM_UNLOAD_CONTEXT 0x11 - -/* - * PMU model specific commands (may not be supported on all PMU models) - */ -#define PFM_WRITE_IBRS 0x20 -#define PFM_WRITE_DBRS 0x21 - -/* - * context flags - */ -#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */ -#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ -#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */ - -/* - * event set flags - */ -#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */ - -/* - * PMC flags - */ -#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ -#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */ - -/* - * PMD/PMC/IBR/DBR return flags (ignored on input) - * - * Those flags are used on output and must be checked in case EAGAIN is returned - * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. - */ -#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */ -#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */ -#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) - -#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) - -typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */ - -/* - * Request structure used to define a context - */ -typedef struct { - pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ - unsigned long ctx_flags; /* noblock/block */ - unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */ - unsigned short ctx_reserved1; /* for future use */ - int ctx_fd; /* return arg: unique identification for context */ - void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ - unsigned long ctx_reserved2[11];/* for future use */ -} pfarg_context_t; - -/* - * Request structure used to write/read a PMC or PMD - */ -typedef struct { - unsigned int reg_num; /* which register */ - unsigned short reg_set; /* event set for this register */ - unsigned short reg_reserved1; /* for future use */ - - unsigned long reg_value; /* initial pmc/pmd value */ - unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ - - unsigned long reg_long_reset; /* reset after buffer overflow notification */ - unsigned long reg_short_reset; /* reset after counter overflow */ - - unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ - unsigned long reg_random_seed; /* seed value when randomization is used */ - unsigned long reg_random_mask; /* bitmask used to limit random value */ - unsigned long reg_last_reset_val;/* return: PMD last reset value */ - - unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ - unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ - - unsigned long reg_reserved2[3]; /* for future use */ -} pfarg_reg_t; - -typedef struct { - unsigned int dbreg_num; /* which debug register */ - unsigned short dbreg_set; /* event set for this register */ - unsigned short dbreg_reserved1; /* for future use */ - unsigned long dbreg_value; /* value for debug register */ - unsigned long dbreg_flags; /* return: dbreg error */ - unsigned long dbreg_reserved2[1]; /* for future use */ -} pfarg_dbreg_t; - -typedef struct { - unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ - unsigned int ft_reserved; /* reserved for future use */ - unsigned long reserved[4]; /* for future use */ -} pfarg_features_t; - -typedef struct { - pid_t load_pid; /* process to load the context into */ - unsigned short load_set; /* first event set to load */ - unsigned short load_reserved1; /* for future use */ - unsigned long load_reserved2[3]; /* for future use */ -} pfarg_load_t; - -typedef struct { - int msg_type; /* generic message header */ - int msg_ctx_fd; /* generic message header */ - unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ - unsigned short msg_active_set; /* active set at the time of overflow */ - unsigned short msg_reserved1; /* for future use */ - unsigned int msg_reserved2; /* for future use */ - unsigned long msg_tstamp; /* for perf tuning/debug */ -} pfm_ovfl_msg_t; - -typedef struct { - int msg_type; /* generic message header */ - int msg_ctx_fd; /* generic message header */ - unsigned long msg_tstamp; /* for perf tuning */ -} pfm_end_msg_t; - -typedef struct { - int msg_type; /* type of the message */ - int msg_ctx_fd; /* unique identifier for the context */ - unsigned long msg_tstamp; /* for perf tuning */ -} pfm_gen_msg_t; - -#define PFM_MSG_OVFL 1 /* an overflow happened */ -#define PFM_MSG_END 2 /* task to which context was attached ended */ - -typedef union { - pfm_ovfl_msg_t pfm_ovfl_msg; - pfm_end_msg_t pfm_end_msg; - pfm_gen_msg_t pfm_gen_msg; -} pfm_msg_t; - -/* - * Define the version numbers for both perfmon as a whole and the sampling buffer format. - */ -#define PFM_VERSION_MAJ 2U -#define PFM_VERSION_MIN 0U -#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) -#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) -#define PFM_VERSION_MINOR(x) ((x) & 0xffff) +#include <uapi/asm/perfmon.h> -/* - * miscellaneous architected definitions - */ -#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */ -#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */ -#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */ - -#ifdef __KERNEL__ - extern long perfmonctl(int fd, int cmd, void *arg, int narg); typedef struct { @@ -274,6 +107,4 @@ typedef struct { extern pfm_sysctl_t pfm_sysctl; -#endif /* __KERNEL__ */ - #endif /* _ASM_IA64_PERFMON_H */ diff --git a/arch/ia64/include/asm/ptrace.h b/arch/ia64/include/asm/ptrace.h index 68c98f5b3ca6..b0e973649cb9 100644 --- a/arch/ia64/include/asm/ptrace.h +++ b/arch/ia64/include/asm/ptrace.h @@ -1,6 +1,3 @@ -#ifndef _ASM_IA64_PTRACE_H -#define _ASM_IA64_PTRACE_H - /* * Copyright (C) 1998-2004 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> @@ -15,52 +12,13 @@ * 6/17/99 D. Mosberger added second unat member to "struct switch_stack" * */ -/* - * When a user process is blocked, its state looks as follows: - * - * +----------------------+ ------- IA64_STK_OFFSET - * | | ^ - * | struct pt_regs | | - * | | | - * +----------------------+ | - * | | | - * | memory stack | | - * | (growing downwards) | | - * //.....................// | - * | - * //.....................// | - * | | | - * +----------------------+ | - * | struct switch_stack | | - * | | | - * +----------------------+ | - * | | | - * //.....................// | - * | - * //.....................// | - * | | | - * | register stack | | - * | (growing upwards) | | - * | | | - * +----------------------+ | --- IA64_RBS_OFFSET - * | struct thread_info | | ^ - * +----------------------+ | | - * | | | | - * | struct task_struct | | | - * current -> | | | | - * +----------------------+ ------- - * - * Note that ar.ec is not saved explicitly in pt_reg or switch_stack. - * This is because ar.ec is saved as part of ar.pfs. - */ - - -#include <asm/fpu.h> +#ifndef _ASM_IA64_PTRACE_H +#define _ASM_IA64_PTRACE_H -#ifdef __KERNEL__ #ifndef ASM_OFFSETS_C #include <asm/asm-offsets.h> #endif +#include <uapi/asm/ptrace.h> /* * Base-2 logarithm of number of pages to allocate per task structure @@ -81,155 +39,8 @@ #define KERNEL_STACK_SIZE IA64_STK_OFFSET -#endif /* __KERNEL__ */ - #ifndef __ASSEMBLY__ -/* - * This struct defines the way the registers are saved on system - * calls. - * - * We don't save all floating point register because the kernel - * is compiled to use only a very small subset, so the other are - * untouched. - * - * THIS STRUCTURE MUST BE A MULTIPLE 16-BYTE IN SIZE - * (because the memory stack pointer MUST ALWAYS be aligned this way) - * - */ -struct pt_regs { - /* The following registers are saved by SAVE_MIN: */ - unsigned long b6; /* scratch */ - unsigned long b7; /* scratch */ - - unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ - unsigned long ar_ssd; /* reserved for future use (scratch) */ - - unsigned long r8; /* scratch (return value register 0) */ - unsigned long r9; /* scratch (return value register 1) */ - unsigned long r10; /* scratch (return value register 2) */ - unsigned long r11; /* scratch (return value register 3) */ - - unsigned long cr_ipsr; /* interrupted task's psr */ - unsigned long cr_iip; /* interrupted task's instruction pointer */ - /* - * interrupted task's function state; if bit 63 is cleared, it - * contains syscall's ar.pfs.pfm: - */ - unsigned long cr_ifs; - - unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ - unsigned long ar_pfs; /* prev function state */ - unsigned long ar_rsc; /* RSE configuration */ - /* The following two are valid only if cr_ipsr.cpl > 0 || ti->flags & _TIF_MCA_INIT */ - unsigned long ar_rnat; /* RSE NaT */ - unsigned long ar_bspstore; /* RSE bspstore */ - - unsigned long pr; /* 64 predicate registers (1 bit each) */ - unsigned long b0; /* return pointer (bp) */ - unsigned long loadrs; /* size of dirty partition << 16 */ - - unsigned long r1; /* the gp pointer */ - unsigned long r12; /* interrupted task's memory stack pointer */ - unsigned long r13; /* thread pointer */ - - unsigned long ar_fpsr; /* floating point status (preserved) */ - unsigned long r15; /* scratch */ - - /* The remaining registers are NOT saved for system calls. */ - - unsigned long r14; /* scratch */ - unsigned long r2; /* scratch */ - unsigned long r3; /* scratch */ - - /* The following registers are saved by SAVE_REST: */ - unsigned long r16; /* scratch */ - unsigned long r17; /* scratch */ - unsigned long r18; /* scratch */ - unsigned long r19; /* scratch */ - unsigned long r20; /* scratch */ - unsigned long r21; /* scratch */ - unsigned long r22; /* scratch */ - unsigned long r23; /* scratch */ - unsigned long r24; /* scratch */ - unsigned long r25; /* scratch */ - unsigned long r26; /* scratch */ - unsigned long r27; /* scratch */ - unsigned long r28; /* scratch */ - unsigned long r29; /* scratch */ - unsigned long r30; /* scratch */ - unsigned long r31; /* scratch */ - - unsigned long ar_ccv; /* compare/exchange value (scratch) */ - - /* - * Floating point registers that the kernel considers scratch: - */ - struct ia64_fpreg f6; /* scratch */ - struct ia64_fpreg f7; /* scratch */ - struct ia64_fpreg f8; /* scratch */ - struct ia64_fpreg f9; /* scratch */ - struct ia64_fpreg f10; /* scratch */ - struct ia64_fpreg f11; /* scratch */ -}; - -/* - * This structure contains the addition registers that need to - * preserved across a context switch. This generally consists of - * "preserved" registers. - */ -struct switch_stack { - unsigned long caller_unat; /* user NaT collection register (preserved) */ - unsigned long ar_fpsr; /* floating-point status register */ - - struct ia64_fpreg f2; /* preserved */ - struct ia64_fpreg f3; /* preserved */ - struct ia64_fpreg f4; /* preserved */ - struct ia64_fpreg f5; /* preserved */ - - struct ia64_fpreg f12; /* scratch, but untouched by kernel */ - struct ia64_fpreg f13; /* scratch, but untouched by kernel */ - struct ia64_fpreg f14; /* scratch, but untouched by kernel */ - struct ia64_fpreg f15; /* scratch, but untouched by kernel */ - struct ia64_fpreg f16; /* preserved */ - struct ia64_fpreg f17; /* preserved */ - struct ia64_fpreg f18; /* preserved */ - struct ia64_fpreg f19; /* preserved */ - struct ia64_fpreg f20; /* preserved */ - struct ia64_fpreg f21; /* preserved */ - struct ia64_fpreg f22; /* preserved */ - struct ia64_fpreg f23; /* preserved */ - struct ia64_fpreg f24; /* preserved */ - struct ia64_fpreg f25; /* preserved */ - struct ia64_fpreg f26; /* preserved */ - struct ia64_fpreg f27; /* preserved */ - struct ia64_fpreg f28; /* preserved */ - struct ia64_fpreg f29; /* preserved */ - struct ia64_fpreg f30; /* preserved */ - struct ia64_fpreg f31; /* preserved */ - - unsigned long r4; /* preserved */ - unsigned long r5; /* preserved */ - unsigned long r6; /* preserved */ - unsigned long r7; /* preserved */ - - unsigned long b0; /* so we can force a direct return in copy_thread */ - unsigned long b1; - unsigned long b2; - unsigned long b3; - unsigned long b4; - unsigned long b5; - - unsigned long ar_pfs; /* previous function state */ - unsigned long ar_lc; /* loop counter (preserved) */ - unsigned long ar_unat; /* NaT bits for r4-r7 */ - unsigned long ar_rnat; /* RSE NaT collection register */ - unsigned long ar_bspstore; /* RSE dirty base (preserved) */ - unsigned long pr; /* 64 predicate registers (1 bit each) */ -}; - -#ifdef __KERNEL__ - #include <asm/current.h> #include <asm/page.h> @@ -331,46 +142,5 @@ static inline long regs_return_value(struct pt_regs *regs) #define arch_has_single_step() (1) #define arch_has_block_step() (1) -#endif /* !__KERNEL__ */ - -/* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */ -struct pt_all_user_regs { - unsigned long nat; - unsigned long cr_iip; - unsigned long cfm; - unsigned long cr_ipsr; - unsigned long pr; - - unsigned long gr[32]; - unsigned long br[8]; - unsigned long ar[128]; - struct ia64_fpreg fr[128]; -}; - #endif /* !__ASSEMBLY__ */ - -/* indices to application-registers array in pt_all_user_regs */ -#define PT_AUR_RSC 16 -#define PT_AUR_BSP 17 -#define PT_AUR_BSPSTORE 18 -#define PT_AUR_RNAT 19 -#define PT_AUR_CCV 32 -#define PT_AUR_UNAT 36 -#define PT_AUR_FPSR 40 -#define PT_AUR_PFS 64 -#define PT_AUR_LC 65 -#define PT_AUR_EC 66 - -/* - * The numbers chosen here are somewhat arbitrary but absolutely MUST - * not overlap with any of the number assigned in <linux/ptrace.h>. - */ -#define PTRACE_SINGLEBLOCK 12 /* resume execution until next branch */ -#define PTRACE_OLD_GETSIGINFO 13 /* (replaced by PTRACE_GETSIGINFO in <linux/ptrace.h>) */ -#define PTRACE_OLD_SETSIGINFO 14 /* (replaced by PTRACE_SETSIGINFO in <linux/ptrace.h>) */ -#define PTRACE_GETREGS 18 /* get all registers (pt_all_user_regs) in one shot */ -#define PTRACE_SETREGS 19 /* set all registers (pt_all_user_regs) in one shot */ - -#define PTRACE_OLDSETOPTIONS 21 - #endif /* _ASM_IA64_PTRACE_H */ diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h index c8fcaa2ac48f..6f2e2dd0f28f 100644 --- a/arch/ia64/include/asm/siginfo.h +++ b/arch/ia64/include/asm/siginfo.h @@ -1,124 +1,14 @@ -#ifndef _ASM_IA64_SIGINFO_H -#define _ASM_IA64_SIGINFO_H - /* * Based on <asm-i386/siginfo.h>. * * Modified 1998-2002 * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co */ +#ifndef _ASM_IA64_SIGINFO_H +#define _ASM_IA64_SIGINFO_H -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) - -#define HAVE_ARCH_SIGINFO_T -#define HAVE_ARCH_COPY_SIGINFO -#define HAVE_ARCH_COPY_SIGINFO_TO_USER - -#include <asm-generic/siginfo.h> - -typedef struct siginfo { - int si_signo; - int si_errno; - int si_code; - int __pad0; - - union { - int _pad[SI_PAD_SIZE]; - - /* kill() */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof(__ARCH_SI_UID_T) - sizeof(int)]; - sigval_t _sigval; /* must overlay ._rt._sigval! */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - pid_t _pid; /* which child */ - uid_t _uid; /* sender's uid */ - int _status; /* exit code */ - clock_t _utime; - clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - void __user *_addr; /* faulting insn/memory ref. */ - int _imm; /* immediate value for "break" */ - unsigned int _flags; /* see below */ - unsigned long _isr; /* isr */ - short _addr_lsb; /* lsb of faulting address */ - } _sigfault; - - /* SIGPOLL */ - struct { - long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ - int _fd; - } _sigpoll; - } _sifields; -} siginfo_t; - -#define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */ -#define si_flags _sifields._sigfault._flags -/* - * si_isr is valid for SIGILL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP provided that - * si_code is non-zero and __ISR_VALID is set in si_flags. - */ -#define si_isr _sifields._sigfault._isr - -/* - * Flag values for si_flags: - */ -#define __ISR_VALID_BIT 0 -#define __ISR_VALID (1 << __ISR_VALID_BIT) - -/* - * SIGILL si_codes - */ -#define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */ -#define __ILL_BREAK (__SI_FAULT|10) /* illegal break */ -#define __ILL_BNDMOD (__SI_FAULT|11) /* bundle-update (modification) in progress */ -#undef NSIGILL -#define NSIGILL 11 - -/* - * SIGFPE si_codes - */ -#define __FPE_DECOVF (__SI_FAULT|9) /* decimal overflow */ -#define __FPE_DECDIV (__SI_FAULT|10) /* decimal division by zero */ -#define __FPE_DECERR (__SI_FAULT|11) /* packed decimal error */ -#define __FPE_INVASC (__SI_FAULT|12) /* invalid ASCII digit */ -#define __FPE_INVDEC (__SI_FAULT|13) /* invalid decimal digit */ -#undef NSIGFPE -#define NSIGFPE 13 - -/* - * SIGSEGV si_codes - */ -#define __SEGV_PSTKOVF (__SI_FAULT|3) /* paragraph stack overflow */ -#undef NSIGSEGV -#define NSIGSEGV 3 - -#undef NSIGTRAP -#define NSIGTRAP 4 - -#ifdef __KERNEL__ #include <linux/string.h> +#include <uapi/asm/siginfo.h> static inline void copy_siginfo (siginfo_t *to, siginfo_t *from) @@ -130,6 +20,4 @@ copy_siginfo (siginfo_t *to, siginfo_t *from) memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); } -#endif /* __KERNEL__ */ - #endif /* _ASM_IA64_SIGINFO_H */ diff --git a/arch/ia64/include/asm/signal.h b/arch/ia64/include/asm/signal.h index b166248d49a4..aecda5b9eb4e 100644 --- a/arch/ia64/include/asm/signal.h +++ b/arch/ia64/include/asm/signal.h @@ -1,6 +1,3 @@ -#ifndef _ASM_IA64_SIGNAL_H -#define _ASM_IA64_SIGNAL_H - /* * Modified 1998-2001, 2003 * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co @@ -8,129 +5,18 @@ * Unfortunately, this file is being included by bits/signal.h in * glibc-2.x. Hence the #ifdef __KERNEL__ ugliness. */ +#ifndef _ASM_IA64_SIGNAL_H +#define _ASM_IA64_SIGNAL_H -#define SIGHUP 1 -#define SIGINT 2 -#define SIGQUIT 3 -#define SIGILL 4 -#define SIGTRAP 5 -#define SIGABRT 6 -#define SIGIOT 6 -#define SIGBUS 7 -#define SIGFPE 8 -#define SIGKILL 9 -#define SIGUSR1 10 -#define SIGSEGV 11 -#define SIGUSR2 12 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGTERM 15 -#define SIGSTKFLT 16 -#define SIGCHLD 17 -#define SIGCONT 18 -#define SIGSTOP 19 -#define SIGTSTP 20 -#define SIGTTIN 21 -#define SIGTTOU 22 -#define SIGURG 23 -#define SIGXCPU 24 -#define SIGXFSZ 25 -#define SIGVTALRM 26 -#define SIGPROF 27 -#define SIGWINCH 28 -#define SIGIO 29 -#define SIGPOLL SIGIO -/* -#define SIGLOST 29 -*/ -#define SIGPWR 30 -#define SIGSYS 31 -/* signal 31 is no longer "unused", but the SIGUNUSED macro remains for backwards compatibility */ -#define SIGUNUSED 31 - -/* These should not be considered constants from userland. */ -#define SIGRTMIN 32 -#define SIGRTMAX _NSIG - -/* - * SA_FLAGS values: - * - * SA_ONSTACK indicates that a registered stack_t will be used. - * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. - * SA_RESETHAND clears the handler when the signal is delivered. - * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. - * SA_NODEFER prevents the current signal from being masked in the handler. - * - * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single - * Unix names RESETHAND and NODEFER respectively. - */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND - -#define SA_RESTORER 0x04000000 - -/* - * sigaltstack controls - */ -#define SS_ONSTACK 1 -#define SS_DISABLE 2 - -/* - * The minimum stack size needs to be fairly large because we want to - * be sure that an app compiled for today's CPUs will continue to run - * on all future CPU models. The CPU model matters because the signal - * frame needs to have space for the complete machine state, including - * all physical stacked registers. The number of physical stacked - * registers is CPU model dependent, but given that the width of - * ar.rsc.loadrs is 14 bits, we can assume that they'll never take up - * more than 16KB of space. - */ -#if 1 - /* - * This is a stupid typo: the value was _meant_ to be 131072 (0x20000), but I typed it - * in wrong. ;-( To preserve backwards compatibility, we leave the kernel at the - * incorrect value and fix libc only. - */ -# define MINSIGSTKSZ 131027 /* min. stack size for sigaltstack() */ -#else -# define MINSIGSTKSZ 131072 /* min. stack size for sigaltstack() */ -#endif -#define SIGSTKSZ 262144 /* default stack size for sigaltstack() */ +#include <uapi/asm/signal.h> -#ifdef __KERNEL__ #define _NSIG 64 #define _NSIG_BPW 64 #define _NSIG_WORDS (_NSIG / _NSIG_BPW) -#endif /* __KERNEL__ */ - -#include <asm-generic/signal-defs.h> - # ifndef __ASSEMBLY__ -# include <linux/types.h> - -/* Avoid too many header ordering problems. */ -struct siginfo; - -typedef struct sigaltstack { - void __user *ss_sp; - int ss_flags; - size_t ss_size; -} stack_t; - -#ifdef __KERNEL__ - /* Most things should be clean enough to redefine this at will, if care is taken to make libc match. */ @@ -154,7 +40,5 @@ struct k_sigaction { #define ptrace_signal_deliver(regs, cookie) do { } while (0) -#endif /* __KERNEL__ */ - # endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_SIGNAL_H */ diff --git a/arch/ia64/include/asm/termios.h b/arch/ia64/include/asm/termios.h index 689d218c0c28..a42f870ca4f6 100644 --- a/arch/ia64/include/asm/termios.h +++ b/arch/ia64/include/asm/termios.h @@ -1,52 +1,14 @@ -#ifndef _ASM_IA64_TERMIOS_H -#define _ASM_IA64_TERMIOS_H - /* * Modified 1999 * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co * * 99/01/28 Added N_IRDA and N_SMSBLOCK */ +#ifndef _ASM_IA64_TERMIOS_H +#define _ASM_IA64_TERMIOS_H -#include <asm/termbits.h> -#include <asm/ioctls.h> - -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +#include <uapi/asm/termios.h> -# ifdef __KERNEL__ /* intr=^C quit=^\ erase=del kill=^U eof=^D vtime=\0 vmin=\1 sxtc=\0 @@ -92,6 +54,4 @@ struct termio { #define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) #define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) -# endif /* __KERNEL__ */ - #endif /* _ASM_IA64_TERMIOS_H */ diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h index f7ee85378311..ff2ae4136584 100644 --- a/arch/ia64/include/asm/thread_info.h +++ b/arch/ia64/include/asm/thread_info.h @@ -106,7 +106,6 @@ struct thread_info { #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_NOTIFY_RESUME 6 /* resumption notification requested */ -#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_MCA_INIT 18 /* this task is processing MCA or INIT */ #define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */ @@ -119,7 +118,6 @@ struct thread_info { #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_MCA_INIT (1 << TIF_MCA_INIT) #define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED) #define _TIF_RESTORE_RSE (1 << TIF_RESTORE_RSE) diff --git a/arch/ia64/include/asm/types.h b/arch/ia64/include/asm/types.h index 3f5b122d9975..4c351b169da2 100644 --- a/arch/ia64/include/asm/types.h +++ b/arch/ia64/include/asm/types.h @@ -1,6 +1,3 @@ -#ifndef _ASM_IA64_TYPES_H -#define _ASM_IA64_TYPES_H - /* * This file is never included by application software unless explicitly * requested (e.g., via linux/types.h) in which case the application is @@ -13,32 +10,22 @@ * Modified 1998-2000, 2002 * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co */ +#ifndef _ASM_IA64_TYPES_H +#define _ASM_IA64_TYPES_H -#ifdef __KERNEL__ #include <asm-generic/int-ll64.h> -#else -#include <asm-generic/int-l64.h> -#endif +#include <uapi/asm/types.h> #ifdef __ASSEMBLY__ -# define __IA64_UL(x) (x) -# define __IA64_UL_CONST(x) x - #else -# define __IA64_UL(x) ((unsigned long)(x)) -# define __IA64_UL_CONST(x) x##UL - /* * These aren't exported outside the kernel to avoid name space clashes */ -# ifdef __KERNEL__ struct fnptr { unsigned long ip; unsigned long gp; }; -# endif /* __KERNEL__ */ #endif /* !__ASSEMBLY__ */ - #endif /* _ASM_IA64_TYPES_H */ diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 7a3bd2524944..8b3ff2f5b861 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -1,331 +1,14 @@ -#ifndef _ASM_IA64_UNISTD_H -#define _ASM_IA64_UNISTD_H - /* * IA-64 Linux syscall numbers and inline-functions. * * Copyright (C) 1998-2005 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> */ +#ifndef _ASM_IA64_UNISTD_H +#define _ASM_IA64_UNISTD_H -#include <asm/break.h> - -#define __BREAK_SYSCALL __IA64_BREAK_SYSCALL - -#define __NR_ni_syscall 1024 -#define __NR_exit 1025 -#define __NR_read 1026 -#define __NR_write 1027 -#define __NR_open 1028 -#define __NR_close 1029 -#define __NR_creat 1030 -#define __NR_link 1031 -#define __NR_unlink 1032 -#define __NR_execve 1033 -#define __NR_chdir 1034 -#define __NR_fchdir 1035 -#define __NR_utimes 1036 -#define __NR_mknod 1037 -#define __NR_chmod 1038 -#define __NR_chown 1039 -#define __NR_lseek 1040 -#define __NR_getpid 1041 -#define __NR_getppid 1042 -#define __NR_mount 1043 -#define __NR_umount 1044 -#define __NR_setuid 1045 -#define __NR_getuid 1046 -#define __NR_geteuid 1047 -#define __NR_ptrace 1048 -#define __NR_access 1049 -#define __NR_sync 1050 -#define __NR_fsync 1051 -#define __NR_fdatasync 1052 -#define __NR_kill 1053 -#define __NR_rename 1054 -#define __NR_mkdir 1055 -#define __NR_rmdir 1056 -#define __NR_dup 1057 -#define __NR_pipe 1058 -#define __NR_times 1059 -#define __NR_brk 1060 -#define __NR_setgid 1061 -#define __NR_getgid 1062 -#define __NR_getegid 1063 -#define __NR_acct 1064 -#define __NR_ioctl 1065 -#define __NR_fcntl 1066 -#define __NR_umask 1067 -#define __NR_chroot 1068 -#define __NR_ustat 1069 -#define __NR_dup2 1070 -#define __NR_setreuid 1071 -#define __NR_setregid 1072 -#define __NR_getresuid 1073 -#define __NR_setresuid 1074 -#define __NR_getresgid 1075 -#define __NR_setresgid 1076 -#define __NR_getgroups 1077 -#define __NR_setgroups 1078 -#define __NR_getpgid 1079 -#define __NR_setpgid 1080 -#define __NR_setsid 1081 -#define __NR_getsid 1082 -#define __NR_sethostname 1083 -#define __NR_setrlimit 1084 -#define __NR_getrlimit 1085 -#define __NR_getrusage 1086 -#define __NR_gettimeofday 1087 -#define __NR_settimeofday 1088 -#define __NR_select 1089 -#define __NR_poll 1090 -#define __NR_symlink 1091 -#define __NR_readlink 1092 -#define __NR_uselib 1093 -#define __NR_swapon 1094 -#define __NR_swapoff 1095 -#define __NR_reboot 1096 -#define __NR_truncate 1097 -#define __NR_ftruncate 1098 -#define __NR_fchmod 1099 -#define __NR_fchown 1100 -#define __NR_getpriority 1101 -#define __NR_setpriority 1102 -#define __NR_statfs 1103 -#define __NR_fstatfs 1104 -#define __NR_gettid 1105 -#define __NR_semget 1106 -#define __NR_semop 1107 -#define __NR_semctl 1108 -#define __NR_msgget 1109 -#define __NR_msgsnd 1110 -#define __NR_msgrcv 1111 -#define __NR_msgctl 1112 -#define __NR_shmget 1113 -#define __NR_shmat 1114 -#define __NR_shmdt 1115 -#define __NR_shmctl 1116 -/* also known as klogctl() in GNU libc: */ -#define __NR_syslog 1117 -#define __NR_setitimer 1118 -#define __NR_getitimer 1119 -/* 1120 was __NR_old_stat */ -/* 1121 was __NR_old_lstat */ -/* 1122 was __NR_old_fstat */ -#define __NR_vhangup 1123 -#define __NR_lchown 1124 -#define __NR_remap_file_pages 1125 -#define __NR_wait4 1126 -#define __NR_sysinfo 1127 -#define __NR_clone 1128 -#define __NR_setdomainname 1129 -#define __NR_uname 1130 -#define __NR_adjtimex 1131 -/* 1132 was __NR_create_module */ -#define __NR_init_module 1133 -#define __NR_delete_module 1134 -/* 1135 was __NR_get_kernel_syms */ -/* 1136 was __NR_query_module */ -#define __NR_quotactl 1137 -#define __NR_bdflush 1138 -#define __NR_sysfs 1139 -#define __NR_personality 1140 -#define __NR_afs_syscall 1141 -#define __NR_setfsuid 1142 -#define __NR_setfsgid 1143 -#define __NR_getdents 1144 -#define __NR_flock 1145 -#define __NR_readv 1146 -#define __NR_writev 1147 -#define __NR_pread64 1148 -#define __NR_pwrite64 1149 -#define __NR__sysctl 1150 -#define __NR_mmap 1151 -#define __NR_munmap 1152 -#define __NR_mlock 1153 -#define __NR_mlockall 1154 -#define __NR_mprotect 1155 -#define __NR_mremap 1156 -#define __NR_msync 1157 -#define __NR_munlock 1158 -#define __NR_munlockall 1159 -#define __NR_sched_getparam 1160 -#define __NR_sched_setparam 1161 -#define __NR_sched_getscheduler 1162 -#define __NR_sched_setscheduler 1163 -#define __NR_sched_yield 1164 -#define __NR_sched_get_priority_max 1165 -#define __NR_sched_get_priority_min 1166 -#define __NR_sched_rr_get_interval 1167 -#define __NR_nanosleep 1168 -#define __NR_nfsservctl 1169 -#define __NR_prctl 1170 -/* 1171 is reserved for backwards compatibility with old __NR_getpagesize */ -#define __NR_mmap2 1172 -#define __NR_pciconfig_read 1173 -#define __NR_pciconfig_write 1174 -#define __NR_perfmonctl 1175 -#define __NR_sigaltstack 1176 -#define __NR_rt_sigaction 1177 -#define __NR_rt_sigpending 1178 -#define __NR_rt_sigprocmask 1179 -#define __NR_rt_sigqueueinfo 1180 -#define __NR_rt_sigreturn 1181 -#define __NR_rt_sigsuspend 1182 -#define __NR_rt_sigtimedwait 1183 -#define __NR_getcwd 1184 -#define __NR_capget 1185 -#define __NR_capset 1186 -#define __NR_sendfile 1187 -#define __NR_getpmsg 1188 -#define __NR_putpmsg 1189 -#define __NR_socket 1190 -#define __NR_bind 1191 -#define __NR_connect 1192 -#define __NR_listen 1193 -#define __NR_accept 1194 -#define __NR_getsockname 1195 -#define __NR_getpeername 1196 -#define __NR_socketpair 1197 -#define __NR_send 1198 -#define __NR_sendto 1199 -#define __NR_recv 1200 -#define __NR_recvfrom 1201 -#define __NR_shutdown 1202 -#define __NR_setsockopt 1203 -#define __NR_getsockopt 1204 -#define __NR_sendmsg 1205 -#define __NR_recvmsg 1206 -#define __NR_pivot_root 1207 -#define __NR_mincore 1208 -#define __NR_madvise 1209 -#define __NR_stat 1210 -#define __NR_lstat 1211 -#define __NR_fstat 1212 -#define __NR_clone2 1213 -#define __NR_getdents64 1214 -#define __NR_getunwind 1215 -#define __NR_readahead 1216 -#define __NR_setxattr 1217 -#define __NR_lsetxattr 1218 -#define __NR_fsetxattr 1219 -#define __NR_getxattr 1220 -#define __NR_lgetxattr 1221 -#define __NR_fgetxattr 1222 -#define __NR_listxattr 1223 -#define __NR_llistxattr 1224 -#define __NR_flistxattr 1225 -#define __NR_removexattr 1226 -#define __NR_lremovexattr 1227 -#define __NR_fremovexattr 1228 -#define __NR_tkill 1229 -#define __NR_futex 1230 -#define __NR_sched_setaffinity 1231 -#define __NR_sched_getaffinity 1232 -#define __NR_set_tid_address 1233 -#define __NR_fadvise64 1234 -#define __NR_tgkill 1235 -#define __NR_exit_group 1236 -#define __NR_lookup_dcookie 1237 -#define __NR_io_setup 1238 -#define __NR_io_destroy 1239 -#define __NR_io_getevents 1240 -#define __NR_io_submit 1241 -#define __NR_io_cancel 1242 -#define __NR_epoll_create 1243 -#define __NR_epoll_ctl 1244 -#define __NR_epoll_wait 1245 -#define __NR_restart_syscall 1246 -#define __NR_semtimedop 1247 -#define __NR_timer_create 1248 -#define __NR_timer_settime 1249 -#define __NR_timer_gettime 1250 -#define __NR_timer_getoverrun 1251 -#define __NR_timer_delete 1252 -#define __NR_clock_settime 1253 -#define __NR_clock_gettime 1254 -#define __NR_clock_getres 1255 -#define __NR_clock_nanosleep 1256 -#define __NR_fstatfs64 1257 -#define __NR_statfs64 1258 -#define __NR_mbind 1259 -#define __NR_get_mempolicy 1260 -#define __NR_set_mempolicy 1261 -#define __NR_mq_open 1262 -#define __NR_mq_unlink 1263 -#define __NR_mq_timedsend 1264 -#define __NR_mq_timedreceive 1265 -#define __NR_mq_notify 1266 -#define __NR_mq_getsetattr 1267 -#define __NR_kexec_load 1268 -#define __NR_vserver 1269 -#define __NR_waitid 1270 -#define __NR_add_key 1271 -#define __NR_request_key 1272 -#define __NR_keyctl 1273 -#define __NR_ioprio_set 1274 -#define __NR_ioprio_get 1275 -#define __NR_move_pages 1276 -#define __NR_inotify_init 1277 -#define __NR_inotify_add_watch 1278 -#define __NR_inotify_rm_watch 1279 -#define __NR_migrate_pages 1280 -#define __NR_openat 1281 -#define __NR_mkdirat 1282 -#define __NR_mknodat 1283 -#define __NR_fchownat 1284 -#define __NR_futimesat 1285 -#define __NR_newfstatat 1286 -#define __NR_unlinkat 1287 -#define __NR_renameat 1288 -#define __NR_linkat 1289 -#define __NR_symlinkat 1290 -#define __NR_readlinkat 1291 -#define __NR_fchmodat 1292 -#define __NR_faccessat 1293 -#define __NR_pselect6 1294 -#define __NR_ppoll 1295 -#define __NR_unshare 1296 -#define __NR_splice 1297 -#define __NR_set_robust_list 1298 -#define __NR_get_robust_list 1299 -#define __NR_sync_file_range 1300 -#define __NR_tee 1301 -#define __NR_vmsplice 1302 -#define __NR_fallocate 1303 -#define __NR_getcpu 1304 -#define __NR_epoll_pwait 1305 -#define __NR_utimensat 1306 -#define __NR_signalfd 1307 -#define __NR_timerfd 1308 -#define __NR_eventfd 1309 -#define __NR_timerfd_create 1310 -#define __NR_timerfd_settime 1311 -#define __NR_timerfd_gettime 1312 -#define __NR_signalfd4 1313 -#define __NR_eventfd2 1314 -#define __NR_epoll_create1 1315 -#define __NR_dup3 1316 -#define __NR_pipe2 1317 -#define __NR_inotify_init1 1318 -#define __NR_preadv 1319 -#define __NR_pwritev 1320 -#define __NR_rt_tgsigqueueinfo 1321 -#define __NR_recvmmsg 1322 -#define __NR_fanotify_init 1323 -#define __NR_fanotify_mark 1324 -#define __NR_prlimit64 1325 -#define __NR_name_to_handle_at 1326 -#define __NR_open_by_handle_at 1327 -#define __NR_clock_adjtime 1328 -#define __NR_syncfs 1329 -#define __NR_setns 1330 -#define __NR_sendmmsg 1331 -#define __NR_process_vm_readv 1332 -#define __NR_process_vm_writev 1333 -#define __NR_accept4 1334 +#include <uapi/asm/unistd.h> -#ifdef __KERNEL__ #define NR_syscalls 311 /* length of syscall table */ @@ -382,5 +65,4 @@ asmlinkage long sys_rt_sigaction(int sig, #define cond_syscall(x) asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall"))) #endif /* !__ASSEMBLY__ */ -#endif /* __KERNEL__ */ #endif /* _ASM_IA64_UNISTD_H */ diff --git a/arch/ia64/include/asm/ustack.h b/arch/ia64/include/asm/ustack.h index 504167c35b8b..b275401b96d3 100644 --- a/arch/ia64/include/asm/ustack.h +++ b/arch/ia64/include/asm/ustack.h @@ -1,20 +1,11 @@ #ifndef _ASM_IA64_USTACK_H #define _ASM_IA64_USTACK_H -/* - * Constants for the user stack size - */ - -#ifdef __KERNEL__ #include <asm/page.h> +#include <uapi/asm/ustack.h> /* The absolute hard limit for stack size is 1/2 of the mappable space in the region */ #define MAX_USER_STACK_SIZE (RGN_MAP_LIMIT/2) #define STACK_TOP (0x6000000000000000UL + RGN_MAP_LIMIT) #define STACK_TOP_MAX STACK_TOP -#endif - -/* Make a default stack size of 2GiB */ -#define DEFAULT_USER_STACK_SIZE (1UL << 31) - #endif /* _ASM_IA64_USTACK_H */ diff --git a/arch/ia64/include/uapi/asm/Kbuild b/arch/ia64/include/uapi/asm/Kbuild index baebb3da1d44..30cafac93703 100644 --- a/arch/ia64/include/uapi/asm/Kbuild +++ b/arch/ia64/include/uapi/asm/Kbuild @@ -1,3 +1,48 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +header-y += auxvec.h +header-y += bitsperlong.h +header-y += break.h +header-y += byteorder.h +header-y += cmpxchg.h +header-y += errno.h +header-y += fcntl.h +header-y += fpu.h +header-y += gcc_intrin.h +header-y += ia64regs.h +header-y += intel_intrin.h +header-y += intrinsics.h +header-y += ioctl.h +header-y += ioctls.h +header-y += ipcbuf.h +header-y += kvm.h +header-y += kvm_para.h +header-y += mman.h +header-y += msgbuf.h +header-y += param.h +header-y += perfmon.h +header-y += perfmon_default_smpl.h +header-y += poll.h +header-y += posix_types.h +header-y += ptrace.h +header-y += ptrace_offsets.h +header-y += resource.h +header-y += rse.h +header-y += sembuf.h +header-y += setup.h +header-y += shmbuf.h +header-y += sigcontext.h +header-y += siginfo.h +header-y += signal.h +header-y += socket.h +header-y += sockios.h +header-y += stat.h +header-y += statfs.h +header-y += swab.h +header-y += termbits.h +header-y += termios.h +header-y += types.h +header-y += ucontext.h +header-y += unistd.h +header-y += ustack.h diff --git a/arch/ia64/include/asm/auxvec.h b/arch/ia64/include/uapi/asm/auxvec.h index 58277fc650ef..58277fc650ef 100644 --- a/arch/ia64/include/asm/auxvec.h +++ b/arch/ia64/include/uapi/asm/auxvec.h diff --git a/arch/ia64/include/asm/bitsperlong.h b/arch/ia64/include/uapi/asm/bitsperlong.h index ec4db3c970b7..ec4db3c970b7 100644 --- a/arch/ia64/include/asm/bitsperlong.h +++ b/arch/ia64/include/uapi/asm/bitsperlong.h diff --git a/arch/ia64/include/asm/break.h b/arch/ia64/include/uapi/asm/break.h index e90c40ec9edf..e90c40ec9edf 100644 --- a/arch/ia64/include/asm/break.h +++ b/arch/ia64/include/uapi/asm/break.h diff --git a/arch/ia64/include/asm/byteorder.h b/arch/ia64/include/uapi/asm/byteorder.h index a8dd73558150..a8dd73558150 100644 --- a/arch/ia64/include/asm/byteorder.h +++ b/arch/ia64/include/uapi/asm/byteorder.h diff --git a/arch/ia64/include/asm/cmpxchg.h b/arch/ia64/include/uapi/asm/cmpxchg.h index 4f37dbbb8640..4f37dbbb8640 100644 --- a/arch/ia64/include/asm/cmpxchg.h +++ b/arch/ia64/include/uapi/asm/cmpxchg.h diff --git a/arch/ia64/include/asm/errno.h b/arch/ia64/include/uapi/asm/errno.h index 4c82b503d92f..4c82b503d92f 100644 --- a/arch/ia64/include/asm/errno.h +++ b/arch/ia64/include/uapi/asm/errno.h diff --git a/arch/ia64/include/asm/fcntl.h b/arch/ia64/include/uapi/asm/fcntl.h index 1dd275dc8f65..1dd275dc8f65 100644 --- a/arch/ia64/include/asm/fcntl.h +++ b/arch/ia64/include/uapi/asm/fcntl.h diff --git a/arch/ia64/include/asm/fpu.h b/arch/ia64/include/uapi/asm/fpu.h index b6395ad1500a..b6395ad1500a 100644 --- a/arch/ia64/include/asm/fpu.h +++ b/arch/ia64/include/uapi/asm/fpu.h diff --git a/arch/ia64/include/uapi/asm/gcc_intrin.h b/arch/ia64/include/uapi/asm/gcc_intrin.h new file mode 100644 index 000000000000..61d0d0111978 --- /dev/null +++ b/arch/ia64/include/uapi/asm/gcc_intrin.h @@ -0,0 +1,618 @@ +/* + * + * Copyright (C) 2002,2003 Jun Nakajima <jun.nakajima@intel.com> + * Copyright (C) 2002,2003 Suresh Siddha <suresh.b.siddha@intel.com> + */ +#ifndef _UAPI_ASM_IA64_GCC_INTRIN_H +#define _UAPI_ASM_IA64_GCC_INTRIN_H + +#include <linux/types.h> +#include <linux/compiler.h> + +/* define this macro to get some asm stmts included in 'c' files */ +#define ASM_SUPPORTED + +/* Optimization barrier */ +/* The "volatile" is due to gcc bugs */ +#define ia64_barrier() asm volatile ("":::"memory") + +#define ia64_stop() asm volatile (";;"::) + +#define ia64_invala_gr(regnum) asm volatile ("invala.e r%0" :: "i"(regnum)) + +#define ia64_invala_fr(regnum) asm volatile ("invala.e f%0" :: "i"(regnum)) + +#define ia64_flushrs() asm volatile ("flushrs;;":::"memory") + +#define ia64_loadrs() asm volatile ("loadrs;;":::"memory") + +extern void ia64_bad_param_for_setreg (void); +extern void ia64_bad_param_for_getreg (void); + + +#define ia64_native_setreg(regnum, val) \ +({ \ + switch (regnum) { \ + case _IA64_REG_PSR_L: \ + asm volatile ("mov psr.l=%0" :: "r"(val) : "memory"); \ + break; \ + case _IA64_REG_AR_KR0 ... _IA64_REG_AR_EC: \ + asm volatile ("mov ar%0=%1" :: \ + "i" (regnum - _IA64_REG_AR_KR0), \ + "r"(val): "memory"); \ + break; \ + case _IA64_REG_CR_DCR ... _IA64_REG_CR_LRR1: \ + asm volatile ("mov cr%0=%1" :: \ + "i" (regnum - _IA64_REG_CR_DCR), \ + "r"(val): "memory" ); \ + break; \ + case _IA64_REG_SP: \ + asm volatile ("mov r12=%0" :: \ + "r"(val): "memory"); \ + break; \ + case _IA64_REG_GP: \ + asm volatile ("mov gp=%0" :: "r"(val) : "memory"); \ + break; \ + default: \ + ia64_bad_param_for_setreg(); \ + break; \ + } \ +}) + +#define ia64_native_getreg(regnum) \ +({ \ + __u64 ia64_intri_res; \ + \ + switch (regnum) { \ + case _IA64_REG_GP: \ + asm volatile ("mov %0=gp" : "=r"(ia64_intri_res)); \ + break; \ + case _IA64_REG_IP: \ + asm volatile ("mov %0=ip" : "=r"(ia64_intri_res)); \ + break; \ + case _IA64_REG_PSR: \ + asm volatile ("mov %0=psr" : "=r"(ia64_intri_res)); \ + break; \ + case _IA64_REG_TP: /* for current() */ \ + ia64_intri_res = ia64_r13; \ + break; \ + case _IA64_REG_AR_KR0 ... _IA64_REG_AR_EC: \ + asm volatile ("mov %0=ar%1" : "=r" (ia64_intri_res) \ + : "i"(regnum - _IA64_REG_AR_KR0)); \ + break; \ + case _IA64_REG_CR_DCR ... _IA64_REG_CR_LRR1: \ + asm volatile ("mov %0=cr%1" : "=r" (ia64_intri_res) \ + : "i" (regnum - _IA64_REG_CR_DCR)); \ + break; \ + case _IA64_REG_SP: \ + asm volatile ("mov %0=sp" : "=r" (ia64_intri_res)); \ + break; \ + default: \ + ia64_bad_param_for_getreg(); \ + break; \ + } \ + ia64_intri_res; \ +}) + +#define ia64_hint_pause 0 + +#define ia64_hint(mode) \ +({ \ + switch (mode) { \ + case ia64_hint_pause: \ + asm volatile ("hint @pause" ::: "memory"); \ + break; \ + } \ +}) + + +/* Integer values for mux1 instruction */ +#define ia64_mux1_brcst 0 +#define ia64_mux1_mix 8 +#define ia64_mux1_shuf 9 +#define ia64_mux1_alt 10 +#define ia64_mux1_rev 11 + +#define ia64_mux1(x, mode) \ +({ \ + __u64 ia64_intri_res; \ + \ + switch (mode) { \ + case ia64_mux1_brcst: \ + asm ("mux1 %0=%1,@brcst" : "=r" (ia64_intri_res) : "r" (x)); \ + break; \ + case ia64_mux1_mix: \ + asm ("mux1 %0=%1,@mix" : "=r" (ia64_intri_res) : "r" (x)); \ + break; \ + case ia64_mux1_shuf: \ + asm ("mux1 %0=%1,@shuf" : "=r" (ia64_intri_res) : "r" (x)); \ + break; \ + case ia64_mux1_alt: \ + asm ("mux1 %0=%1,@alt" : "=r" (ia64_intri_res) : "r" (x)); \ + break; \ + case ia64_mux1_rev: \ + asm ("mux1 %0=%1,@rev" : "=r" (ia64_intri_res) : "r" (x)); \ + break; \ + } \ + ia64_intri_res; \ +}) + +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# define ia64_popcnt(x) __builtin_popcountl(x) +#else +# define ia64_popcnt(x) \ + ({ \ + __u64 ia64_intri_res; \ + asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \ + \ + ia64_intri_res; \ + }) +#endif + +#define ia64_getf_exp(x) \ +({ \ + long ia64_intri_res; \ + \ + asm ("getf.exp %0=%1" : "=r"(ia64_intri_res) : "f"(x)); \ + \ + ia64_intri_res; \ +}) + +#define ia64_shrp(a, b, count) \ +({ \ + __u64 ia64_intri_res; \ + asm ("shrp %0=%1,%2,%3" : "=r"(ia64_intri_res) : "r"(a), "r"(b), "i"(count)); \ + ia64_intri_res; \ +}) + +#define ia64_ldfs(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("ldfs %0=[%1]" :"=f"(__f__): "r"(x)); \ +}) + +#define ia64_ldfd(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("ldfd %0=[%1]" :"=f"(__f__): "r"(x)); \ +}) + +#define ia64_ldfe(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("ldfe %0=[%1]" :"=f"(__f__): "r"(x)); \ +}) + +#define ia64_ldf8(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("ldf8 %0=[%1]" :"=f"(__f__): "r"(x)); \ +}) + +#define ia64_ldf_fill(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("ldf.fill %0=[%1]" :"=f"(__f__): "r"(x)); \ +}) + +#define ia64_st4_rel_nta(m, val) \ +({ \ + asm volatile ("st4.rel.nta [%0] = %1\n\t" :: "r"(m), "r"(val)); \ +}) + +#define ia64_stfs(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("stfs [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +#define ia64_stfd(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("stfd [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +#define ia64_stfe(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +#define ia64_stf8(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +#define ia64_stf_spill(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + asm volatile ("stf.spill [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +#define ia64_fetchadd4_acq(p, inc) \ +({ \ + \ + __u64 ia64_intri_res; \ + asm volatile ("fetchadd4.acq %0=[%1],%2" \ + : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ + : "memory"); \ + \ + ia64_intri_res; \ +}) + +#define ia64_fetchadd4_rel(p, inc) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("fetchadd4.rel %0=[%1],%2" \ + : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ + : "memory"); \ + \ + ia64_intri_res; \ +}) + +#define ia64_fetchadd8_acq(p, inc) \ +({ \ + \ + __u64 ia64_intri_res; \ + asm volatile ("fetchadd8.acq %0=[%1],%2" \ + : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ + : "memory"); \ + \ + ia64_intri_res; \ +}) + +#define ia64_fetchadd8_rel(p, inc) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("fetchadd8.rel %0=[%1],%2" \ + : "=r"(ia64_intri_res) : "r"(p), "i" (inc) \ + : "memory"); \ + \ + ia64_intri_res; \ +}) + +#define ia64_xchg1(ptr,x) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("xchg1 %0=[%1],%2" \ + : "=r" (ia64_intri_res) : "r" (ptr), "r" (x) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_xchg2(ptr,x) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("xchg2 %0=[%1],%2" : "=r" (ia64_intri_res) \ + : "r" (ptr), "r" (x) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_xchg4(ptr,x) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("xchg4 %0=[%1],%2" : "=r" (ia64_intri_res) \ + : "r" (ptr), "r" (x) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_xchg8(ptr,x) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("xchg8 %0=[%1],%2" : "=r" (ia64_intri_res) \ + : "r" (ptr), "r" (x) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg1_acq(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + asm volatile ("cmpxchg1.acq %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg1_rel(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + asm volatile ("cmpxchg1.rel %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg2_acq(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + asm volatile ("cmpxchg2.acq %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg2_rel(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + \ + asm volatile ("cmpxchg2.rel %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg4_acq(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + asm volatile ("cmpxchg4.acq %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg4_rel(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + asm volatile ("cmpxchg4.rel %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg8_acq(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + asm volatile ("cmpxchg8.acq %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_cmpxchg8_rel(ptr, new, old) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \ + \ + asm volatile ("cmpxchg8.rel %0=[%1],%2,ar.ccv": \ + "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \ + ia64_intri_res; \ +}) + +#define ia64_mf() asm volatile ("mf" ::: "memory") +#define ia64_mfa() asm volatile ("mf.a" ::: "memory") + +#define ia64_invala() asm volatile ("invala" ::: "memory") + +#define ia64_native_thash(addr) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("thash %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \ + ia64_intri_res; \ +}) + +#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory") +#define ia64_srlz_d() asm volatile (";; srlz.d" ::: "memory"); + +#ifdef HAVE_SERIALIZE_DIRECTIVE +# define ia64_dv_serialize_data() asm volatile (".serialize.data"); +# define ia64_dv_serialize_instruction() asm volatile (".serialize.instruction"); +#else +# define ia64_dv_serialize_data() +# define ia64_dv_serialize_instruction() +#endif + +#define ia64_nop(x) asm volatile ("nop %0"::"i"(x)); + +#define ia64_itci(addr) asm volatile ("itc.i %0;;" :: "r"(addr) : "memory") + +#define ia64_itcd(addr) asm volatile ("itc.d %0;;" :: "r"(addr) : "memory") + + +#define ia64_itri(trnum, addr) asm volatile ("itr.i itr[%0]=%1" \ + :: "r"(trnum), "r"(addr) : "memory") + +#define ia64_itrd(trnum, addr) asm volatile ("itr.d dtr[%0]=%1" \ + :: "r"(trnum), "r"(addr) : "memory") + +#define ia64_tpa(addr) \ +({ \ + unsigned long ia64_pa; \ + asm volatile ("tpa %0 = %1" : "=r"(ia64_pa) : "r"(addr) : "memory"); \ + ia64_pa; \ +}) + +#define __ia64_set_dbr(index, val) \ + asm volatile ("mov dbr[%0]=%1" :: "r"(index), "r"(val) : "memory") + +#define ia64_set_ibr(index, val) \ + asm volatile ("mov ibr[%0]=%1" :: "r"(index), "r"(val) : "memory") + +#define ia64_set_pkr(index, val) \ + asm volatile ("mov pkr[%0]=%1" :: "r"(index), "r"(val) : "memory") + +#define ia64_set_pmc(index, val) \ + asm volatile ("mov pmc[%0]=%1" :: "r"(index), "r"(val) : "memory") + +#define ia64_set_pmd(index, val) \ + asm volatile ("mov pmd[%0]=%1" :: "r"(index), "r"(val) : "memory") + +#define ia64_native_set_rr(index, val) \ + asm volatile ("mov rr[%0]=%1" :: "r"(index), "r"(val) : "memory"); + +#define ia64_native_get_cpuid(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=cpuid[%r1]" : "=r"(ia64_intri_res) : "rO"(index)); \ + ia64_intri_res; \ +}) + +#define __ia64_get_dbr(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=dbr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ +}) + +#define ia64_get_ibr(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=ibr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ +}) + +#define ia64_get_pkr(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=pkr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ +}) + +#define ia64_get_pmc(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=pmc[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ +}) + + +#define ia64_native_get_pmd(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=pmd[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ +}) + +#define ia64_native_get_rr(index) \ +({ \ + unsigned long ia64_intri_res; \ + asm volatile ("mov %0=rr[%1]" : "=r"(ia64_intri_res) : "r" (index)); \ + ia64_intri_res; \ +}) + +#define ia64_native_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory") + + +#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory") + +#define ia64_native_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory") +#define ia64_native_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory") +#define ia64_sum(mask) asm volatile ("sum %0":: "i"((mask)) : "memory") +#define ia64_rum(mask) asm volatile ("rum %0":: "i"((mask)) : "memory") + +#define ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr)) + +#define ia64_native_ptcga(addr, size) \ +do { \ + asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory"); \ + ia64_dv_serialize_data(); \ +} while (0) + +#define ia64_ptcl(addr, size) \ +do { \ + asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(size) : "memory"); \ + ia64_dv_serialize_data(); \ +} while (0) + +#define ia64_ptri(addr, size) \ + asm volatile ("ptr.i %0,%1" :: "r"(addr), "r"(size) : "memory") + +#define ia64_ptrd(addr, size) \ + asm volatile ("ptr.d %0,%1" :: "r"(addr), "r"(size) : "memory") + +#define ia64_ttag(addr) \ +({ \ + __u64 ia64_intri_res; \ + asm volatile ("ttag %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \ + ia64_intri_res; \ +}) + + +/* Values for lfhint in ia64_lfetch and ia64_lfetch_fault */ + +#define ia64_lfhint_none 0 +#define ia64_lfhint_nt1 1 +#define ia64_lfhint_nt2 2 +#define ia64_lfhint_nta 3 + +#define ia64_lfetch(lfhint, y) \ +({ \ + switch (lfhint) { \ + case ia64_lfhint_none: \ + asm volatile ("lfetch [%0]" : : "r"(y)); \ + break; \ + case ia64_lfhint_nt1: \ + asm volatile ("lfetch.nt1 [%0]" : : "r"(y)); \ + break; \ + case ia64_lfhint_nt2: \ + asm volatile ("lfetch.nt2 [%0]" : : "r"(y)); \ + break; \ + case ia64_lfhint_nta: \ + asm volatile ("lfetch.nta [%0]" : : "r"(y)); \ + break; \ + } \ +}) + +#define ia64_lfetch_excl(lfhint, y) \ +({ \ + switch (lfhint) { \ + case ia64_lfhint_none: \ + asm volatile ("lfetch.excl [%0]" :: "r"(y)); \ + break; \ + case ia64_lfhint_nt1: \ + asm volatile ("lfetch.excl.nt1 [%0]" :: "r"(y)); \ + break; \ + case ia64_lfhint_nt2: \ + asm volatile ("lfetch.excl.nt2 [%0]" :: "r"(y)); \ + break; \ + case ia64_lfhint_nta: \ + asm volatile ("lfetch.excl.nta [%0]" :: "r"(y)); \ + break; \ + } \ +}) + +#define ia64_lfetch_fault(lfhint, y) \ +({ \ + switch (lfhint) { \ + case ia64_lfhint_none: \ + asm volatile ("lfetch.fault [%0]" : : "r"(y)); \ + break; \ + case ia64_lfhint_nt1: \ + asm volatile ("lfetch.fault.nt1 [%0]" : : "r"(y)); \ + break; \ + case ia64_lfhint_nt2: \ + asm volatile ("lfetch.fault.nt2 [%0]" : : "r"(y)); \ + break; \ + case ia64_lfhint_nta: \ + asm volatile ("lfetch.fault.nta [%0]" : : "r"(y)); \ + break; \ + } \ +}) + +#define ia64_lfetch_fault_excl(lfhint, y) \ +({ \ + switch (lfhint) { \ + case ia64_lfhint_none: \ + asm volatile ("lfetch.fault.excl [%0]" :: "r"(y)); \ + break; \ + case ia64_lfhint_nt1: \ + asm volatile ("lfetch.fault.excl.nt1 [%0]" :: "r"(y)); \ + break; \ + case ia64_lfhint_nt2: \ + asm volatile ("lfetch.fault.excl.nt2 [%0]" :: "r"(y)); \ + break; \ + case ia64_lfhint_nta: \ + asm volatile ("lfetch.fault.excl.nta [%0]" :: "r"(y)); \ + break; \ + } \ +}) + +#define ia64_native_intrin_local_irq_restore(x) \ +do { \ + asm volatile (";; cmp.ne p6,p7=%0,r0;;" \ + "(p6) ssm psr.i;" \ + "(p7) rsm psr.i;;" \ + "(p6) srlz.d" \ + :: "r"((x)) : "p6", "p7", "memory"); \ +} while (0) + +#endif /* _UAPI_ASM_IA64_GCC_INTRIN_H */ diff --git a/arch/ia64/include/asm/ia64regs.h b/arch/ia64/include/uapi/asm/ia64regs.h index 1757f1c11ad4..1757f1c11ad4 100644 --- a/arch/ia64/include/asm/ia64regs.h +++ b/arch/ia64/include/uapi/asm/ia64regs.h diff --git a/arch/ia64/include/asm/intel_intrin.h b/arch/ia64/include/uapi/asm/intel_intrin.h index 53cec577558a..53cec577558a 100644 --- a/arch/ia64/include/asm/intel_intrin.h +++ b/arch/ia64/include/uapi/asm/intel_intrin.h diff --git a/arch/ia64/include/uapi/asm/intrinsics.h b/arch/ia64/include/uapi/asm/intrinsics.h new file mode 100644 index 000000000000..5829978ff466 --- /dev/null +++ b/arch/ia64/include/uapi/asm/intrinsics.h @@ -0,0 +1,124 @@ +/* + * Compiler-dependent intrinsics. + * + * Copyright (C) 2002-2003 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + */ +#ifndef _UAPI_ASM_IA64_INTRINSICS_H +#define _UAPI_ASM_IA64_INTRINSICS_H + + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> +/* include compiler specific intrinsics */ +#include <asm/ia64regs.h> +#ifdef __INTEL_COMPILER +# include <asm/intel_intrin.h> +#else +# include <asm/gcc_intrin.h> +#endif +#include <asm/cmpxchg.h> + +#define ia64_native_get_psr_i() (ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I) + +#define ia64_native_set_rr0_to_rr4(val0, val1, val2, val3, val4) \ +do { \ + ia64_native_set_rr(0x0000000000000000UL, (val0)); \ + ia64_native_set_rr(0x2000000000000000UL, (val1)); \ + ia64_native_set_rr(0x4000000000000000UL, (val2)); \ + ia64_native_set_rr(0x6000000000000000UL, (val3)); \ + ia64_native_set_rr(0x8000000000000000UL, (val4)); \ +} while (0) + +/* + * Force an unresolved reference if someone tries to use + * ia64_fetch_and_add() with a bad value. + */ +extern unsigned long __bad_size_for_ia64_fetch_and_add (void); +extern unsigned long __bad_increment_for_ia64_fetch_and_add (void); + +#define IA64_FETCHADD(tmp,v,n,sz,sem) \ +({ \ + switch (sz) { \ + case 4: \ + tmp = ia64_fetchadd4_##sem((unsigned int *) v, n); \ + break; \ + \ + case 8: \ + tmp = ia64_fetchadd8_##sem((unsigned long *) v, n); \ + break; \ + \ + default: \ + __bad_size_for_ia64_fetch_and_add(); \ + } \ +}) + +#define ia64_fetchadd(i,v,sem) \ +({ \ + __u64 _tmp; \ + volatile __typeof__(*(v)) *_v = (v); \ + /* Can't use a switch () here: gcc isn't always smart enough for that... */ \ + if ((i) == -16) \ + IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v)), sem); \ + else if ((i) == -8) \ + IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v)), sem); \ + else if ((i) == -4) \ + IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v)), sem); \ + else if ((i) == -1) \ + IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v)), sem); \ + else if ((i) == 1) \ + IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v)), sem); \ + else if ((i) == 4) \ + IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v)), sem); \ + else if ((i) == 8) \ + IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v)), sem); \ + else if ((i) == 16) \ + IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v)), sem); \ + else \ + _tmp = __bad_increment_for_ia64_fetch_and_add(); \ + (__typeof__(*(v))) (_tmp); /* return old value */ \ +}) + +#define ia64_fetch_and_add(i,v) (ia64_fetchadd(i, v, rel) + (i)) /* return new value */ + +#endif + + +#ifndef __ASSEMBLY__ + +#define IA64_INTRINSIC_API(name) ia64_native_ ## name +#define IA64_INTRINSIC_MACRO(name) ia64_native_ ## name + + +/************************************************/ +/* Instructions paravirtualized for correctness */ +/************************************************/ +/* fc, thash, get_cpuid, get_pmd, get_eflags, set_eflags */ +/* Note that "ttag" and "cover" are also privilege-sensitive; "ttag" + * is not currently used (though it may be in a long-format VHPT system!) + */ +#define ia64_fc IA64_INTRINSIC_API(fc) +#define ia64_thash IA64_INTRINSIC_API(thash) +#define ia64_get_cpuid IA64_INTRINSIC_API(get_cpuid) +#define ia64_get_pmd IA64_INTRINSIC_API(get_pmd) + + +/************************************************/ +/* Instructions paravirtualized for performance */ +/************************************************/ +#define ia64_ssm IA64_INTRINSIC_MACRO(ssm) +#define ia64_rsm IA64_INTRINSIC_MACRO(rsm) +#define ia64_getreg IA64_INTRINSIC_MACRO(getreg) +#define ia64_setreg IA64_INTRINSIC_API(setreg) +#define ia64_set_rr IA64_INTRINSIC_API(set_rr) +#define ia64_get_rr IA64_INTRINSIC_API(get_rr) +#define ia64_ptcga IA64_INTRINSIC_API(ptcga) +#define ia64_get_psr_i IA64_INTRINSIC_API(get_psr_i) +#define ia64_intrin_local_irq_restore \ + IA64_INTRINSIC_API(intrin_local_irq_restore) +#define ia64_set_rr0_to_rr4 IA64_INTRINSIC_API(set_rr0_to_rr4) + +#endif /* !__ASSEMBLY__ */ + +#endif /* _UAPI_ASM_IA64_INTRINSICS_H */ diff --git a/arch/ia64/include/asm/ioctl.h b/arch/ia64/include/uapi/asm/ioctl.h index b279fe06dfe5..b279fe06dfe5 100644 --- a/arch/ia64/include/asm/ioctl.h +++ b/arch/ia64/include/uapi/asm/ioctl.h diff --git a/arch/ia64/include/asm/ioctls.h b/arch/ia64/include/uapi/asm/ioctls.h index f3aab5512e98..f3aab5512e98 100644 --- a/arch/ia64/include/asm/ioctls.h +++ b/arch/ia64/include/uapi/asm/ioctls.h diff --git a/arch/ia64/include/asm/ipcbuf.h b/arch/ia64/include/uapi/asm/ipcbuf.h index 84c7e51cb6d0..84c7e51cb6d0 100644 --- a/arch/ia64/include/asm/ipcbuf.h +++ b/arch/ia64/include/uapi/asm/ipcbuf.h diff --git a/arch/ia64/include/asm/kvm.h b/arch/ia64/include/uapi/asm/kvm.h index ec6c6b301238..ec6c6b301238 100644 --- a/arch/ia64/include/asm/kvm.h +++ b/arch/ia64/include/uapi/asm/kvm.h diff --git a/arch/ia64/include/uapi/asm/kvm_para.h b/arch/ia64/include/uapi/asm/kvm_para.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/arch/ia64/include/uapi/asm/kvm_para.h diff --git a/arch/ia64/include/uapi/asm/mman.h b/arch/ia64/include/uapi/asm/mman.h new file mode 100644 index 000000000000..8740819adc54 --- /dev/null +++ b/arch/ia64/include/uapi/asm/mman.h @@ -0,0 +1,16 @@ +/* + * Based on <asm-i386/mman.h>. + * + * Modified 1998-2000, 2002 + * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co + */ +#ifndef _UAPI_ASM_IA64_MMAN_H +#define _UAPI_ASM_IA64_MMAN_H + + +#include <asm-generic/mman.h> + +#define MAP_GROWSUP 0x0200 /* register stack-like segment */ + + +#endif /* _UAPI_ASM_IA64_MMAN_H */ diff --git a/arch/ia64/include/asm/msgbuf.h b/arch/ia64/include/uapi/asm/msgbuf.h index 6c64c0d2aae1..6c64c0d2aae1 100644 --- a/arch/ia64/include/asm/msgbuf.h +++ b/arch/ia64/include/uapi/asm/msgbuf.h diff --git a/arch/ia64/include/uapi/asm/param.h b/arch/ia64/include/uapi/asm/param.h new file mode 100644 index 000000000000..d7da41d9497d --- /dev/null +++ b/arch/ia64/include/uapi/asm/param.h @@ -0,0 +1,29 @@ +/* + * Fundamental kernel parameters. + * + * Based on <asm-i386/param.h>. + * + * Modified 1998, 1999, 2002-2003 + * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co + */ +#ifndef _UAPI_ASM_IA64_PARAM_H +#define _UAPI_ASM_IA64_PARAM_H + + +#define EXEC_PAGESIZE 65536 + +#ifndef NOGROUP +# define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#ifndef __KERNEL__ + /* + * Technically, this is wrong, but some old apps still refer to it. The proper way to + * get the HZ value is via sysconf(_SC_CLK_TCK). + */ +# define HZ 1024 +#endif + +#endif /* _UAPI_ASM_IA64_PARAM_H */ diff --git a/arch/ia64/include/uapi/asm/perfmon.h b/arch/ia64/include/uapi/asm/perfmon.h new file mode 100644 index 000000000000..1a10a2dd58a1 --- /dev/null +++ b/arch/ia64/include/uapi/asm/perfmon.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2001-2003 Hewlett-Packard Co + * Stephane Eranian <eranian@hpl.hp.com> + */ + +#ifndef _UAPI_ASM_IA64_PERFMON_H +#define _UAPI_ASM_IA64_PERFMON_H + +/* + * perfmon commands supported on all CPU models + */ +#define PFM_WRITE_PMCS 0x01 +#define PFM_WRITE_PMDS 0x02 +#define PFM_READ_PMDS 0x03 +#define PFM_STOP 0x04 +#define PFM_START 0x05 +#define PFM_ENABLE 0x06 /* obsolete */ +#define PFM_DISABLE 0x07 /* obsolete */ +#define PFM_CREATE_CONTEXT 0x08 +#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */ +#define PFM_RESTART 0x0a +#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ +#define PFM_GET_FEATURES 0x0c +#define PFM_DEBUG 0x0d +#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ +#define PFM_GET_PMC_RESET_VAL 0x0f +#define PFM_LOAD_CONTEXT 0x10 +#define PFM_UNLOAD_CONTEXT 0x11 + +/* + * PMU model specific commands (may not be supported on all PMU models) + */ +#define PFM_WRITE_IBRS 0x20 +#define PFM_WRITE_DBRS 0x21 + +/* + * context flags + */ +#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */ +#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ +#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */ + +/* + * event set flags + */ +#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */ + +/* + * PMC flags + */ +#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ +#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */ + +/* + * PMD/PMC/IBR/DBR return flags (ignored on input) + * + * Those flags are used on output and must be checked in case EAGAIN is returned + * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. + */ +#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */ +#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */ +#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) + +#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) + +typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */ + +/* + * Request structure used to define a context + */ +typedef struct { + pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ + unsigned long ctx_flags; /* noblock/block */ + unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */ + unsigned short ctx_reserved1; /* for future use */ + int ctx_fd; /* return arg: unique identification for context */ + void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ + unsigned long ctx_reserved2[11];/* for future use */ +} pfarg_context_t; + +/* + * Request structure used to write/read a PMC or PMD + */ +typedef struct { + unsigned int reg_num; /* which register */ + unsigned short reg_set; /* event set for this register */ + unsigned short reg_reserved1; /* for future use */ + + unsigned long reg_value; /* initial pmc/pmd value */ + unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ + + unsigned long reg_long_reset; /* reset after buffer overflow notification */ + unsigned long reg_short_reset; /* reset after counter overflow */ + + unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ + unsigned long reg_random_seed; /* seed value when randomization is used */ + unsigned long reg_random_mask; /* bitmask used to limit random value */ + unsigned long reg_last_reset_val;/* return: PMD last reset value */ + + unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ + unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ + + unsigned long reg_reserved2[3]; /* for future use */ +} pfarg_reg_t; + +typedef struct { + unsigned int dbreg_num; /* which debug register */ + unsigned short dbreg_set; /* event set for this register */ + unsigned short dbreg_reserved1; /* for future use */ + unsigned long dbreg_value; /* value for debug register */ + unsigned long dbreg_flags; /* return: dbreg error */ + unsigned long dbreg_reserved2[1]; /* for future use */ +} pfarg_dbreg_t; + +typedef struct { + unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ + unsigned int ft_reserved; /* reserved for future use */ + unsigned long reserved[4]; /* for future use */ +} pfarg_features_t; + +typedef struct { + pid_t load_pid; /* process to load the context into */ + unsigned short load_set; /* first event set to load */ + unsigned short load_reserved1; /* for future use */ + unsigned long load_reserved2[3]; /* for future use */ +} pfarg_load_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ + unsigned short msg_active_set; /* active set at the time of overflow */ + unsigned short msg_reserved1; /* for future use */ + unsigned int msg_reserved2; /* for future use */ + unsigned long msg_tstamp; /* for perf tuning/debug */ +} pfm_ovfl_msg_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_end_msg_t; + +typedef struct { + int msg_type; /* type of the message */ + int msg_ctx_fd; /* unique identifier for the context */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_gen_msg_t; + +#define PFM_MSG_OVFL 1 /* an overflow happened */ +#define PFM_MSG_END 2 /* task to which context was attached ended */ + +typedef union { + pfm_ovfl_msg_t pfm_ovfl_msg; + pfm_end_msg_t pfm_end_msg; + pfm_gen_msg_t pfm_gen_msg; +} pfm_msg_t; + +/* + * Define the version numbers for both perfmon as a whole and the sampling buffer format. + */ +#define PFM_VERSION_MAJ 2U +#define PFM_VERSION_MIN 0U +#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) +#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) +#define PFM_VERSION_MINOR(x) ((x) & 0xffff) + + +/* + * miscellaneous architected definitions + */ +#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */ +#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */ +#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */ + + +#endif /* _UAPI_ASM_IA64_PERFMON_H */ diff --git a/arch/ia64/include/asm/perfmon_default_smpl.h b/arch/ia64/include/uapi/asm/perfmon_default_smpl.h index a2d560c67230..a2d560c67230 100644 --- a/arch/ia64/include/asm/perfmon_default_smpl.h +++ b/arch/ia64/include/uapi/asm/perfmon_default_smpl.h diff --git a/arch/ia64/include/asm/poll.h b/arch/ia64/include/uapi/asm/poll.h index c98509d3149e..c98509d3149e 100644 --- a/arch/ia64/include/asm/poll.h +++ b/arch/ia64/include/uapi/asm/poll.h diff --git a/arch/ia64/include/asm/posix_types.h b/arch/ia64/include/uapi/asm/posix_types.h index 99ee1d6510cf..99ee1d6510cf 100644 --- a/arch/ia64/include/asm/posix_types.h +++ b/arch/ia64/include/uapi/asm/posix_types.h diff --git a/arch/ia64/include/uapi/asm/ptrace.h b/arch/ia64/include/uapi/asm/ptrace.h new file mode 100644 index 000000000000..0a02f634e12b --- /dev/null +++ b/arch/ia64/include/uapi/asm/ptrace.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 1998-2004 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2003 Intel Co + * Suresh Siddha <suresh.b.siddha@intel.com> + * Fenghua Yu <fenghua.yu@intel.com> + * Arun Sharma <arun.sharma@intel.com> + * + * 12/07/98 S. Eranian added pt_regs & switch_stack + * 12/21/98 D. Mosberger updated to match latest code + * 6/17/99 D. Mosberger added second unat member to "struct switch_stack" + * + */ +#ifndef _UAPI_ASM_IA64_PTRACE_H +#define _UAPI_ASM_IA64_PTRACE_H + +/* + * When a user process is blocked, its state looks as follows: + * + * +----------------------+ ------- IA64_STK_OFFSET + * | | ^ + * | struct pt_regs | | + * | | | + * +----------------------+ | + * | | | + * | memory stack | | + * | (growing downwards) | | + * //.....................// | + * | + * //.....................// | + * | | | + * +----------------------+ | + * | struct switch_stack | | + * | | | + * +----------------------+ | + * | | | + * //.....................// | + * | + * //.....................// | + * | | | + * | register stack | | + * | (growing upwards) | | + * | | | + * +----------------------+ | --- IA64_RBS_OFFSET + * | struct thread_info | | ^ + * +----------------------+ | | + * | | | | + * | struct task_struct | | | + * current -> | | | | + * +----------------------+ ------- + * + * Note that ar.ec is not saved explicitly in pt_reg or switch_stack. + * This is because ar.ec is saved as part of ar.pfs. + */ + + +#include <asm/fpu.h> + + +#ifndef __ASSEMBLY__ + +/* + * This struct defines the way the registers are saved on system + * calls. + * + * We don't save all floating point register because the kernel + * is compiled to use only a very small subset, so the other are + * untouched. + * + * THIS STRUCTURE MUST BE A MULTIPLE 16-BYTE IN SIZE + * (because the memory stack pointer MUST ALWAYS be aligned this way) + * + */ +struct pt_regs { + /* The following registers are saved by SAVE_MIN: */ + unsigned long b6; /* scratch */ + unsigned long b7; /* scratch */ + + unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ + unsigned long ar_ssd; /* reserved for future use (scratch) */ + + unsigned long r8; /* scratch (return value register 0) */ + unsigned long r9; /* scratch (return value register 1) */ + unsigned long r10; /* scratch (return value register 2) */ + unsigned long r11; /* scratch (return value register 3) */ + + unsigned long cr_ipsr; /* interrupted task's psr */ + unsigned long cr_iip; /* interrupted task's instruction pointer */ + /* + * interrupted task's function state; if bit 63 is cleared, it + * contains syscall's ar.pfs.pfm: + */ + unsigned long cr_ifs; + + unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ + unsigned long ar_pfs; /* prev function state */ + unsigned long ar_rsc; /* RSE configuration */ + /* The following two are valid only if cr_ipsr.cpl > 0 || ti->flags & _TIF_MCA_INIT */ + unsigned long ar_rnat; /* RSE NaT */ + unsigned long ar_bspstore; /* RSE bspstore */ + + unsigned long pr; /* 64 predicate registers (1 bit each) */ + unsigned long b0; /* return pointer (bp) */ + unsigned long loadrs; /* size of dirty partition << 16 */ + + unsigned long r1; /* the gp pointer */ + unsigned long r12; /* interrupted task's memory stack pointer */ + unsigned long r13; /* thread pointer */ + + unsigned long ar_fpsr; /* floating point status (preserved) */ + unsigned long r15; /* scratch */ + + /* The remaining registers are NOT saved for system calls. */ + + unsigned long r14; /* scratch */ + unsigned long r2; /* scratch */ + unsigned long r3; /* scratch */ + + /* The following registers are saved by SAVE_REST: */ + unsigned long r16; /* scratch */ + unsigned long r17; /* scratch */ + unsigned long r18; /* scratch */ + unsigned long r19; /* scratch */ + unsigned long r20; /* scratch */ + unsigned long r21; /* scratch */ + unsigned long r22; /* scratch */ + unsigned long r23; /* scratch */ + unsigned long r24; /* scratch */ + unsigned long r25; /* scratch */ + unsigned long r26; /* scratch */ + unsigned long r27; /* scratch */ + unsigned long r28; /* scratch */ + unsigned long r29; /* scratch */ + unsigned long r30; /* scratch */ + unsigned long r31; /* scratch */ + + unsigned long ar_ccv; /* compare/exchange value (scratch) */ + + /* + * Floating point registers that the kernel considers scratch: + */ + struct ia64_fpreg f6; /* scratch */ + struct ia64_fpreg f7; /* scratch */ + struct ia64_fpreg f8; /* scratch */ + struct ia64_fpreg f9; /* scratch */ + struct ia64_fpreg f10; /* scratch */ + struct ia64_fpreg f11; /* scratch */ +}; + +/* + * This structure contains the addition registers that need to + * preserved across a context switch. This generally consists of + * "preserved" registers. + */ +struct switch_stack { + unsigned long caller_unat; /* user NaT collection register (preserved) */ + unsigned long ar_fpsr; /* floating-point status register */ + + struct ia64_fpreg f2; /* preserved */ + struct ia64_fpreg f3; /* preserved */ + struct ia64_fpreg f4; /* preserved */ + struct ia64_fpreg f5; /* preserved */ + + struct ia64_fpreg f12; /* scratch, but untouched by kernel */ + struct ia64_fpreg f13; /* scratch, but untouched by kernel */ + struct ia64_fpreg f14; /* scratch, but untouched by kernel */ + struct ia64_fpreg f15; /* scratch, but untouched by kernel */ + struct ia64_fpreg f16; /* preserved */ + struct ia64_fpreg f17; /* preserved */ + struct ia64_fpreg f18; /* preserved */ + struct ia64_fpreg f19; /* preserved */ + struct ia64_fpreg f20; /* preserved */ + struct ia64_fpreg f21; /* preserved */ + struct ia64_fpreg f22; /* preserved */ + struct ia64_fpreg f23; /* preserved */ + struct ia64_fpreg f24; /* preserved */ + struct ia64_fpreg f25; /* preserved */ + struct ia64_fpreg f26; /* preserved */ + struct ia64_fpreg f27; /* preserved */ + struct ia64_fpreg f28; /* preserved */ + struct ia64_fpreg f29; /* preserved */ + struct ia64_fpreg f30; /* preserved */ + struct ia64_fpreg f31; /* preserved */ + + unsigned long r4; /* preserved */ + unsigned long r5; /* preserved */ + unsigned long r6; /* preserved */ + unsigned long r7; /* preserved */ + + unsigned long b0; /* so we can force a direct return in copy_thread */ + unsigned long b1; + unsigned long b2; + unsigned long b3; + unsigned long b4; + unsigned long b5; + + unsigned long ar_pfs; /* previous function state */ + unsigned long ar_lc; /* loop counter (preserved) */ + unsigned long ar_unat; /* NaT bits for r4-r7 */ + unsigned long ar_rnat; /* RSE NaT collection register */ + unsigned long ar_bspstore; /* RSE dirty base (preserved) */ + unsigned long pr; /* 64 predicate registers (1 bit each) */ +}; + + +/* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */ +struct pt_all_user_regs { + unsigned long nat; + unsigned long cr_iip; + unsigned long cfm; + unsigned long cr_ipsr; + unsigned long pr; + + unsigned long gr[32]; + unsigned long br[8]; + unsigned long ar[128]; + struct ia64_fpreg fr[128]; +}; + +#endif /* !__ASSEMBLY__ */ + +/* indices to application-registers array in pt_all_user_regs */ +#define PT_AUR_RSC 16 +#define PT_AUR_BSP 17 +#define PT_AUR_BSPSTORE 18 +#define PT_AUR_RNAT 19 +#define PT_AUR_CCV 32 +#define PT_AUR_UNAT 36 +#define PT_AUR_FPSR 40 +#define PT_AUR_PFS 64 +#define PT_AUR_LC 65 +#define PT_AUR_EC 66 + +/* + * The numbers chosen here are somewhat arbitrary but absolutely MUST + * not overlap with any of the number assigned in <linux/ptrace.h>. + */ +#define PTRACE_SINGLEBLOCK 12 /* resume execution until next branch */ +#define PTRACE_OLD_GETSIGINFO 13 /* (replaced by PTRACE_GETSIGINFO in <linux/ptrace.h>) */ +#define PTRACE_OLD_SETSIGINFO 14 /* (replaced by PTRACE_SETSIGINFO in <linux/ptrace.h>) */ +#define PTRACE_GETREGS 18 /* get all registers (pt_all_user_regs) in one shot */ +#define PTRACE_SETREGS 19 /* set all registers (pt_all_user_regs) in one shot */ + +#define PTRACE_OLDSETOPTIONS 21 + +#endif /* _UAPI_ASM_IA64_PTRACE_H */ diff --git a/arch/ia64/include/asm/ptrace_offsets.h b/arch/ia64/include/uapi/asm/ptrace_offsets.h index b712773c759e..b712773c759e 100644 --- a/arch/ia64/include/asm/ptrace_offsets.h +++ b/arch/ia64/include/uapi/asm/ptrace_offsets.h diff --git a/arch/ia64/include/asm/resource.h b/arch/ia64/include/uapi/asm/resource.h index ba2272a87fc7..ba2272a87fc7 100644 --- a/arch/ia64/include/asm/resource.h +++ b/arch/ia64/include/uapi/asm/resource.h diff --git a/arch/ia64/include/asm/rse.h b/arch/ia64/include/uapi/asm/rse.h index 02830a3b0196..02830a3b0196 100644 --- a/arch/ia64/include/asm/rse.h +++ b/arch/ia64/include/uapi/asm/rse.h diff --git a/arch/ia64/include/asm/sembuf.h b/arch/ia64/include/uapi/asm/sembuf.h index 1340fbc04d3e..1340fbc04d3e 100644 --- a/arch/ia64/include/asm/sembuf.h +++ b/arch/ia64/include/uapi/asm/sembuf.h diff --git a/arch/ia64/include/asm/setup.h b/arch/ia64/include/uapi/asm/setup.h index 8d56458310b3..8d56458310b3 100644 --- a/arch/ia64/include/asm/setup.h +++ b/arch/ia64/include/uapi/asm/setup.h diff --git a/arch/ia64/include/asm/shmbuf.h b/arch/ia64/include/uapi/asm/shmbuf.h index 585002a77acd..585002a77acd 100644 --- a/arch/ia64/include/asm/shmbuf.h +++ b/arch/ia64/include/uapi/asm/shmbuf.h diff --git a/arch/ia64/include/asm/sigcontext.h b/arch/ia64/include/uapi/asm/sigcontext.h index 57ff777bcc40..57ff777bcc40 100644 --- a/arch/ia64/include/asm/sigcontext.h +++ b/arch/ia64/include/uapi/asm/sigcontext.h diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h new file mode 100644 index 000000000000..4ea6225196bb --- /dev/null +++ b/arch/ia64/include/uapi/asm/siginfo.h @@ -0,0 +1,121 @@ +/* + * Based on <asm-i386/siginfo.h>. + * + * Modified 1998-2002 + * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co + */ +#ifndef _UAPI_ASM_IA64_SIGINFO_H +#define _UAPI_ASM_IA64_SIGINFO_H + + +#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) + +#define HAVE_ARCH_SIGINFO_T +#define HAVE_ARCH_COPY_SIGINFO +#define HAVE_ARCH_COPY_SIGINFO_TO_USER + +#include <asm-generic/siginfo.h> + +typedef struct siginfo { + int si_signo; + int si_errno; + int si_code; + int __pad0; + + union { + int _pad[SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + char _pad[sizeof(__ARCH_SI_UID_T) - sizeof(int)]; + sigval_t _sigval; /* must overlay ._rt._sigval! */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + clock_t _utime; + clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + void __user *_addr; /* faulting insn/memory ref. */ + int _imm; /* immediate value for "break" */ + unsigned int _flags; /* see below */ + unsigned long _isr; /* isr */ + short _addr_lsb; /* lsb of faulting address */ + } _sigfault; + + /* SIGPOLL */ + struct { + long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ + int _fd; + } _sigpoll; + } _sifields; +} siginfo_t; + +#define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */ +#define si_flags _sifields._sigfault._flags +/* + * si_isr is valid for SIGILL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP provided that + * si_code is non-zero and __ISR_VALID is set in si_flags. + */ +#define si_isr _sifields._sigfault._isr + +/* + * Flag values for si_flags: + */ +#define __ISR_VALID_BIT 0 +#define __ISR_VALID (1 << __ISR_VALID_BIT) + +/* + * SIGILL si_codes + */ +#define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */ +#define __ILL_BREAK (__SI_FAULT|10) /* illegal break */ +#define __ILL_BNDMOD (__SI_FAULT|11) /* bundle-update (modification) in progress */ +#undef NSIGILL +#define NSIGILL 11 + +/* + * SIGFPE si_codes + */ +#define __FPE_DECOVF (__SI_FAULT|9) /* decimal overflow */ +#define __FPE_DECDIV (__SI_FAULT|10) /* decimal division by zero */ +#define __FPE_DECERR (__SI_FAULT|11) /* packed decimal error */ +#define __FPE_INVASC (__SI_FAULT|12) /* invalid ASCII digit */ +#define __FPE_INVDEC (__SI_FAULT|13) /* invalid decimal digit */ +#undef NSIGFPE +#define NSIGFPE 13 + +/* + * SIGSEGV si_codes + */ +#define __SEGV_PSTKOVF (__SI_FAULT|3) /* paragraph stack overflow */ +#undef NSIGSEGV +#define NSIGSEGV 3 + +#undef NSIGTRAP +#define NSIGTRAP 4 + + +#endif /* _UAPI_ASM_IA64_SIGINFO_H */ diff --git a/arch/ia64/include/uapi/asm/signal.h b/arch/ia64/include/uapi/asm/signal.h new file mode 100644 index 000000000000..e531c424434c --- /dev/null +++ b/arch/ia64/include/uapi/asm/signal.h @@ -0,0 +1,127 @@ +/* + * Modified 1998-2001, 2003 + * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co + * + * Unfortunately, this file is being included by bits/signal.h in + * glibc-2.x. Hence the #ifdef __KERNEL__ ugliness. + */ +#ifndef _UAPI_ASM_IA64_SIGNAL_H +#define _UAPI_ASM_IA64_SIGNAL_H + + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +/* signal 31 is no longer "unused", but the SIGUNUSED macro remains for backwards compatibility */ +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX _NSIG + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +#define SA_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +/* + * The minimum stack size needs to be fairly large because we want to + * be sure that an app compiled for today's CPUs will continue to run + * on all future CPU models. The CPU model matters because the signal + * frame needs to have space for the complete machine state, including + * all physical stacked registers. The number of physical stacked + * registers is CPU model dependent, but given that the width of + * ar.rsc.loadrs is 14 bits, we can assume that they'll never take up + * more than 16KB of space. + */ +#if 1 + /* + * This is a stupid typo: the value was _meant_ to be 131072 (0x20000), but I typed it + * in wrong. ;-( To preserve backwards compatibility, we leave the kernel at the + * incorrect value and fix libc only. + */ +# define MINSIGSTKSZ 131027 /* min. stack size for sigaltstack() */ +#else +# define MINSIGSTKSZ 131072 /* min. stack size for sigaltstack() */ +#endif +#define SIGSTKSZ 262144 /* default stack size for sigaltstack() */ + + +#include <asm-generic/signal-defs.h> + +# ifndef __ASSEMBLY__ + +# include <linux/types.h> + +/* Avoid too many header ordering problems. */ +struct siginfo; + +typedef struct sigaltstack { + void __user *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + + +# endif /* !__ASSEMBLY__ */ +#endif /* _UAPI_ASM_IA64_SIGNAL_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h index 41fc28a4a18a..41fc28a4a18a 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/uapi/asm/socket.h diff --git a/arch/ia64/include/asm/sockios.h b/arch/ia64/include/uapi/asm/sockios.h index 15c92468ad38..15c92468ad38 100644 --- a/arch/ia64/include/asm/sockios.h +++ b/arch/ia64/include/uapi/asm/sockios.h diff --git a/arch/ia64/include/asm/stat.h b/arch/ia64/include/uapi/asm/stat.h index 367bb90cdffa..367bb90cdffa 100644 --- a/arch/ia64/include/asm/stat.h +++ b/arch/ia64/include/uapi/asm/stat.h diff --git a/arch/ia64/include/asm/statfs.h b/arch/ia64/include/uapi/asm/statfs.h index 1e589669de56..1e589669de56 100644 --- a/arch/ia64/include/asm/statfs.h +++ b/arch/ia64/include/uapi/asm/statfs.h diff --git a/arch/ia64/include/asm/swab.h b/arch/ia64/include/uapi/asm/swab.h index c89a8cb5d8a5..c89a8cb5d8a5 100644 --- a/arch/ia64/include/asm/swab.h +++ b/arch/ia64/include/uapi/asm/swab.h diff --git a/arch/ia64/include/asm/termbits.h b/arch/ia64/include/uapi/asm/termbits.h index c009b94e58d9..c009b94e58d9 100644 --- a/arch/ia64/include/asm/termbits.h +++ b/arch/ia64/include/uapi/asm/termbits.h diff --git a/arch/ia64/include/uapi/asm/termios.h b/arch/ia64/include/uapi/asm/termios.h new file mode 100644 index 000000000000..d59b48c307f8 --- /dev/null +++ b/arch/ia64/include/uapi/asm/termios.h @@ -0,0 +1,50 @@ +/* + * Modified 1999 + * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co + * + * 99/01/28 Added N_IRDA and N_SMSBLOCK + */ +#ifndef _UAPI_ASM_IA64_TERMIOS_H +#define _UAPI_ASM_IA64_TERMIOS_H + + +#include <asm/termbits.h> +#include <asm/ioctls.h> + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + + +#endif /* _UAPI_ASM_IA64_TERMIOS_H */ diff --git a/arch/ia64/include/uapi/asm/types.h b/arch/ia64/include/uapi/asm/types.h new file mode 100644 index 000000000000..321193b05eed --- /dev/null +++ b/arch/ia64/include/uapi/asm/types.h @@ -0,0 +1,31 @@ +/* + * This file is never included by application software unless explicitly + * requested (e.g., via linux/types.h) in which case the application is + * Linux specific so (user-) name space pollution is not a major issue. + * However, for interoperability, libraries still need to be careful to + * avoid naming clashes. + * + * Based on <asm-alpha/types.h>. + * + * Modified 1998-2000, 2002 + * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co + */ +#ifndef _UAPI_ASM_IA64_TYPES_H +#define _UAPI_ASM_IA64_TYPES_H + + +#ifndef __KERNEL__ +#include <asm-generic/int-l64.h> +#endif + +#ifdef __ASSEMBLY__ +# define __IA64_UL(x) (x) +# define __IA64_UL_CONST(x) x + +#else +# define __IA64_UL(x) ((unsigned long)(x)) +# define __IA64_UL_CONST(x) x##UL + +#endif /* !__ASSEMBLY__ */ + +#endif /* _UAPI_ASM_IA64_TYPES_H */ diff --git a/arch/ia64/include/asm/ucontext.h b/arch/ia64/include/uapi/asm/ucontext.h index bf573dc8ca6a..bf573dc8ca6a 100644 --- a/arch/ia64/include/asm/ucontext.h +++ b/arch/ia64/include/uapi/asm/ucontext.h diff --git a/arch/ia64/include/uapi/asm/unistd.h b/arch/ia64/include/uapi/asm/unistd.h new file mode 100644 index 000000000000..b706aa54df20 --- /dev/null +++ b/arch/ia64/include/uapi/asm/unistd.h @@ -0,0 +1,328 @@ +/* + * IA-64 Linux syscall numbers and inline-functions. + * + * Copyright (C) 1998-2005 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + */ +#ifndef _UAPI_ASM_IA64_UNISTD_H +#define _UAPI_ASM_IA64_UNISTD_H + + +#include <asm/break.h> + +#define __BREAK_SYSCALL __IA64_BREAK_SYSCALL + +#define __NR_ni_syscall 1024 +#define __NR_exit 1025 +#define __NR_read 1026 +#define __NR_write 1027 +#define __NR_open 1028 +#define __NR_close 1029 +#define __NR_creat 1030 +#define __NR_link 1031 +#define __NR_unlink 1032 +#define __NR_execve 1033 +#define __NR_chdir 1034 +#define __NR_fchdir 1035 +#define __NR_utimes 1036 +#define __NR_mknod 1037 +#define __NR_chmod 1038 +#define __NR_chown 1039 +#define __NR_lseek 1040 +#define __NR_getpid 1041 +#define __NR_getppid 1042 +#define __NR_mount 1043 +#define __NR_umount 1044 +#define __NR_setuid 1045 +#define __NR_getuid 1046 +#define __NR_geteuid 1047 +#define __NR_ptrace 1048 +#define __NR_access 1049 +#define __NR_sync 1050 +#define __NR_fsync 1051 +#define __NR_fdatasync 1052 +#define __NR_kill 1053 +#define __NR_rename 1054 +#define __NR_mkdir 1055 +#define __NR_rmdir 1056 +#define __NR_dup 1057 +#define __NR_pipe 1058 +#define __NR_times 1059 +#define __NR_brk 1060 +#define __NR_setgid 1061 +#define __NR_getgid 1062 +#define __NR_getegid 1063 +#define __NR_acct 1064 +#define __NR_ioctl 1065 +#define __NR_fcntl 1066 +#define __NR_umask 1067 +#define __NR_chroot 1068 +#define __NR_ustat 1069 +#define __NR_dup2 1070 +#define __NR_setreuid 1071 +#define __NR_setregid 1072 +#define __NR_getresuid 1073 +#define __NR_setresuid 1074 +#define __NR_getresgid 1075 +#define __NR_setresgid 1076 +#define __NR_getgroups 1077 +#define __NR_setgroups 1078 +#define __NR_getpgid 1079 +#define __NR_setpgid 1080 +#define __NR_setsid 1081 +#define __NR_getsid 1082 +#define __NR_sethostname 1083 +#define __NR_setrlimit 1084 +#define __NR_getrlimit 1085 +#define __NR_getrusage 1086 +#define __NR_gettimeofday 1087 +#define __NR_settimeofday 1088 +#define __NR_select 1089 +#define __NR_poll 1090 +#define __NR_symlink 1091 +#define __NR_readlink 1092 +#define __NR_uselib 1093 +#define __NR_swapon 1094 +#define __NR_swapoff 1095 +#define __NR_reboot 1096 +#define __NR_truncate 1097 +#define __NR_ftruncate 1098 +#define __NR_fchmod 1099 +#define __NR_fchown 1100 +#define __NR_getpriority 1101 +#define __NR_setpriority 1102 +#define __NR_statfs 1103 +#define __NR_fstatfs 1104 +#define __NR_gettid 1105 +#define __NR_semget 1106 +#define __NR_semop 1107 +#define __NR_semctl 1108 +#define __NR_msgget 1109 +#define __NR_msgsnd 1110 +#define __NR_msgrcv 1111 +#define __NR_msgctl 1112 +#define __NR_shmget 1113 +#define __NR_shmat 1114 +#define __NR_shmdt 1115 +#define __NR_shmctl 1116 +/* also known as klogctl() in GNU libc: */ +#define __NR_syslog 1117 +#define __NR_setitimer 1118 +#define __NR_getitimer 1119 +/* 1120 was __NR_old_stat */ +/* 1121 was __NR_old_lstat */ +/* 1122 was __NR_old_fstat */ +#define __NR_vhangup 1123 +#define __NR_lchown 1124 +#define __NR_remap_file_pages 1125 +#define __NR_wait4 1126 +#define __NR_sysinfo 1127 +#define __NR_clone 1128 +#define __NR_setdomainname 1129 +#define __NR_uname 1130 +#define __NR_adjtimex 1131 +/* 1132 was __NR_create_module */ +#define __NR_init_module 1133 +#define __NR_delete_module 1134 +/* 1135 was __NR_get_kernel_syms */ +/* 1136 was __NR_query_module */ +#define __NR_quotactl 1137 +#define __NR_bdflush 1138 +#define __NR_sysfs 1139 +#define __NR_personality 1140 +#define __NR_afs_syscall 1141 +#define __NR_setfsuid 1142 +#define __NR_setfsgid 1143 +#define __NR_getdents 1144 +#define __NR_flock 1145 +#define __NR_readv 1146 +#define __NR_writev 1147 +#define __NR_pread64 1148 +#define __NR_pwrite64 1149 +#define __NR__sysctl 1150 +#define __NR_mmap 1151 +#define __NR_munmap 1152 +#define __NR_mlock 1153 +#define __NR_mlockall 1154 +#define __NR_mprotect 1155 +#define __NR_mremap 1156 +#define __NR_msync 1157 +#define __NR_munlock 1158 +#define __NR_munlockall 1159 +#define __NR_sched_getparam 1160 +#define __NR_sched_setparam 1161 +#define __NR_sched_getscheduler 1162 +#define __NR_sched_setscheduler 1163 +#define __NR_sched_yield 1164 +#define __NR_sched_get_priority_max 1165 +#define __NR_sched_get_priority_min 1166 +#define __NR_sched_rr_get_interval 1167 +#define __NR_nanosleep 1168 +#define __NR_nfsservctl 1169 +#define __NR_prctl 1170 +/* 1171 is reserved for backwards compatibility with old __NR_getpagesize */ +#define __NR_mmap2 1172 +#define __NR_pciconfig_read 1173 +#define __NR_pciconfig_write 1174 +#define __NR_perfmonctl 1175 +#define __NR_sigaltstack 1176 +#define __NR_rt_sigaction 1177 +#define __NR_rt_sigpending 1178 +#define __NR_rt_sigprocmask 1179 +#define __NR_rt_sigqueueinfo 1180 +#define __NR_rt_sigreturn 1181 +#define __NR_rt_sigsuspend 1182 +#define __NR_rt_sigtimedwait 1183 +#define __NR_getcwd 1184 +#define __NR_capget 1185 +#define __NR_capset 1186 +#define __NR_sendfile 1187 +#define __NR_getpmsg 1188 +#define __NR_putpmsg 1189 +#define __NR_socket 1190 +#define __NR_bind 1191 +#define __NR_connect 1192 +#define __NR_listen 1193 +#define __NR_accept 1194 +#define __NR_getsockname 1195 +#define __NR_getpeername 1196 +#define __NR_socketpair 1197 +#define __NR_send 1198 +#define __NR_sendto 1199 +#define __NR_recv 1200 +#define __NR_recvfrom 1201 +#define __NR_shutdown 1202 +#define __NR_setsockopt 1203 +#define __NR_getsockopt 1204 +#define __NR_sendmsg 1205 +#define __NR_recvmsg 1206 +#define __NR_pivot_root 1207 +#define __NR_mincore 1208 +#define __NR_madvise 1209 +#define __NR_stat 1210 +#define __NR_lstat 1211 +#define __NR_fstat 1212 +#define __NR_clone2 1213 +#define __NR_getdents64 1214 +#define __NR_getunwind 1215 +#define __NR_readahead 1216 +#define __NR_setxattr 1217 +#define __NR_lsetxattr 1218 +#define __NR_fsetxattr 1219 +#define __NR_getxattr 1220 +#define __NR_lgetxattr 1221 +#define __NR_fgetxattr 1222 +#define __NR_listxattr 1223 +#define __NR_llistxattr 1224 +#define __NR_flistxattr 1225 +#define __NR_removexattr 1226 +#define __NR_lremovexattr 1227 +#define __NR_fremovexattr 1228 +#define __NR_tkill 1229 +#define __NR_futex 1230 +#define __NR_sched_setaffinity 1231 +#define __NR_sched_getaffinity 1232 +#define __NR_set_tid_address 1233 +#define __NR_fadvise64 1234 +#define __NR_tgkill 1235 +#define __NR_exit_group 1236 +#define __NR_lookup_dcookie 1237 +#define __NR_io_setup 1238 +#define __NR_io_destroy 1239 +#define __NR_io_getevents 1240 +#define __NR_io_submit 1241 +#define __NR_io_cancel 1242 +#define __NR_epoll_create 1243 +#define __NR_epoll_ctl 1244 +#define __NR_epoll_wait 1245 +#define __NR_restart_syscall 1246 +#define __NR_semtimedop 1247 +#define __NR_timer_create 1248 +#define __NR_timer_settime 1249 +#define __NR_timer_gettime 1250 +#define __NR_timer_getoverrun 1251 +#define __NR_timer_delete 1252 +#define __NR_clock_settime 1253 +#define __NR_clock_gettime 1254 +#define __NR_clock_getres 1255 +#define __NR_clock_nanosleep 1256 +#define __NR_fstatfs64 1257 +#define __NR_statfs64 1258 +#define __NR_mbind 1259 +#define __NR_get_mempolicy 1260 +#define __NR_set_mempolicy 1261 +#define __NR_mq_open 1262 +#define __NR_mq_unlink 1263 +#define __NR_mq_timedsend 1264 +#define __NR_mq_timedreceive 1265 +#define __NR_mq_notify 1266 +#define __NR_mq_getsetattr 1267 +#define __NR_kexec_load 1268 +#define __NR_vserver 1269 +#define __NR_waitid 1270 +#define __NR_add_key 1271 +#define __NR_request_key 1272 +#define __NR_keyctl 1273 +#define __NR_ioprio_set 1274 +#define __NR_ioprio_get 1275 +#define __NR_move_pages 1276 +#define __NR_inotify_init 1277 +#define __NR_inotify_add_watch 1278 +#define __NR_inotify_rm_watch 1279 +#define __NR_migrate_pages 1280 +#define __NR_openat 1281 +#define __NR_mkdirat 1282 +#define __NR_mknodat 1283 +#define __NR_fchownat 1284 +#define __NR_futimesat 1285 +#define __NR_newfstatat 1286 +#define __NR_unlinkat 1287 +#define __NR_renameat 1288 +#define __NR_linkat 1289 +#define __NR_symlinkat 1290 +#define __NR_readlinkat 1291 +#define __NR_fchmodat 1292 +#define __NR_faccessat 1293 +#define __NR_pselect6 1294 +#define __NR_ppoll 1295 +#define __NR_unshare 1296 +#define __NR_splice 1297 +#define __NR_set_robust_list 1298 +#define __NR_get_robust_list 1299 +#define __NR_sync_file_range 1300 +#define __NR_tee 1301 +#define __NR_vmsplice 1302 +#define __NR_fallocate 1303 +#define __NR_getcpu 1304 +#define __NR_epoll_pwait 1305 +#define __NR_utimensat 1306 +#define __NR_signalfd 1307 +#define __NR_timerfd 1308 +#define __NR_eventfd 1309 +#define __NR_timerfd_create 1310 +#define __NR_timerfd_settime 1311 +#define __NR_timerfd_gettime 1312 +#define __NR_signalfd4 1313 +#define __NR_eventfd2 1314 +#define __NR_epoll_create1 1315 +#define __NR_dup3 1316 +#define __NR_pipe2 1317 +#define __NR_inotify_init1 1318 +#define __NR_preadv 1319 +#define __NR_pwritev 1320 +#define __NR_rt_tgsigqueueinfo 1321 +#define __NR_recvmmsg 1322 +#define __NR_fanotify_init 1323 +#define __NR_fanotify_mark 1324 +#define __NR_prlimit64 1325 +#define __NR_name_to_handle_at 1326 +#define __NR_open_by_handle_at 1327 +#define __NR_clock_adjtime 1328 +#define __NR_syncfs 1329 +#define __NR_setns 1330 +#define __NR_sendmmsg 1331 +#define __NR_process_vm_readv 1332 +#define __NR_process_vm_writev 1333 +#define __NR_accept4 1334 + +#endif /* _UAPI_ASM_IA64_UNISTD_H */ diff --git a/arch/ia64/include/uapi/asm/ustack.h b/arch/ia64/include/uapi/asm/ustack.h new file mode 100644 index 000000000000..1dfebc622692 --- /dev/null +++ b/arch/ia64/include/uapi/asm/ustack.h @@ -0,0 +1,12 @@ +#ifndef _UAPI_ASM_IA64_USTACK_H +#define _UAPI_ASM_IA64_USTACK_H + +/* + * Constants for the user stack size + */ + + +/* Make a default stack size of 2GiB */ +#define DEFAULT_USER_STACK_SIZE (1UL << 31) + +#endif /* _UAPI_ASM_IA64_USTACK_H */ diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index ee31fe9b310e..35e106f2ed13 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -614,14 +614,14 @@ sys_execve (const char __user *filename, const char __user *const __user *envp, struct pt_regs *regs) { - char *fname; + struct filename *fname; int error; fname = getname(filename); error = PTR_ERR(fname); if (IS_ERR(fname)) goto out; - error = do_execve(fname, argv, envp, regs); + error = do_execve(fname->name, argv, envp, regs); putname(fname); out: return error; diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 37dd79511cbe..680b73786be8 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -438,14 +438,6 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) long errno = scr->pt.r8; /* - * In the ia64_leave_kernel code path, 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(&scr->pt)) - return; - - /* * This only loops in the rare cases of handle_signal() failing, in which case we * need to push through a forced SIGSEGV. */ diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 80ff9acc5edf..f6388216080d 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -19,7 +19,7 @@ #include <linux/interrupt.h> #include <linux/efi.h> #include <linux/timex.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/platform_device.h> #include <asm/machvec.h> @@ -454,7 +454,7 @@ void update_vsyscall_tz(void) { } -void update_vsyscall(struct timespec *wall, struct timespec *wtm, +void update_vsyscall_old(struct timespec *wall, struct timespec *wtm, struct clocksource *c, u32 mult) { write_seqcount_begin(&fsyscall_gtod_data.seq); diff --git a/arch/m32r/include/asm/thread_info.h b/arch/m32r/include/asm/thread_info.h index c083f6073ef4..c074f4c2e858 100644 --- a/arch/m32r/include/asm/thread_info.h +++ b/arch/m32r/include/asm/thread_info.h @@ -119,25 +119,20 @@ static inline unsigned int get_thread_fault_code(void) #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */ -#define TIF_IRET 4 /* return with iret */ #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ #define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ -#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) -#define _TIF_IRET (1<<TIF_IRET) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_USEDFPU (1<<TIF_USEDFPU) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) -#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 */ +#define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME) +#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | _TIF_SYSCALL_TRACE) /* * Thread-synchronous status. diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index 384e63f3a4c4..e7366276ef30 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -296,14 +296,14 @@ asmlinkage int sys_execve(const char __user *ufilename, unsigned long r6, struct pt_regs regs) { int error; - char *filename; + struct filename *filename; filename = getname(ufilename); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, uargv, uenvp, ®s); + error = do_execve(filename->name, uargv, uenvp, ®s); putname(filename); out: return error; diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index d0f60b97bbc5..6e3c26a1607c 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -20,7 +20,6 @@ #include <linux/unistd.h> #include <linux/stddef.h> #include <linux/personality.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/cacheflush.h> #include <asm/ucontext.h> @@ -366,6 +365,4 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); } - - clear_thread_flag(TIF_IRET); } diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index dae1e7e16a37..76fd6e2f71da 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -15,6 +15,7 @@ config M68K select FPU if MMU select ARCH_WANT_IPC_PARSE_VERSION select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE + select GENERIC_KERNEL_THREAD config RWSEM_GENERIC_SPINLOCK bool diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index f17c42aff7ff..ae700f49e51d 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -100,6 +100,16 @@ struct thread_struct { .fs = __KERNEL_DS, \ } +/* + * ColdFire stack format sbould be 0x4 for an aligned usp (will always be + * true on thread creation). We need to set this explicitly. + */ +#ifdef CONFIG_COLDFIRE +#define setframeformat(_regs) do { (_regs)->format = 0x4; } while(0) +#else +#define setframeformat(_regs) do { } while (0) +#endif + #ifdef CONFIG_MMU /* * Do necessary setup to start up a newly executed thread. @@ -109,6 +119,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, { regs->pc = pc; regs->sr &= ~0x2000; + setframeformat(regs); wrusp(usp); } @@ -116,21 +127,11 @@ extern int handle_kernel_fault(struct pt_regs *regs); #else -/* - * Coldfire stacks need to be re-aligned on trap exit, conventional - * 68k can handle this case cleanly. - */ -#ifdef CONFIG_COLDFIRE -#define reformat(_regs) do { (_regs)->format = 0x4; } while(0) -#else -#define reformat(_regs) do { } while (0) -#endif - #define start_thread(_regs, _pc, _usp) \ do { \ (_regs)->pc = (_pc); \ ((struct switch_stack *)(_regs))[-1].a6 = 0; \ - reformat(_regs); \ + setframeformat(_regs); \ if (current->mm) \ (_regs)->d5 = current->mm->start_data; \ (_regs)->sr &= ~0x2000; \ @@ -153,8 +154,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - /* * Free current thread data structures etc.. */ diff --git a/arch/m68k/include/asm/ptrace.h b/arch/m68k/include/asm/ptrace.h index 65322b17b6cf..5e08b597f012 100644 --- a/arch/m68k/include/asm/ptrace.h +++ b/arch/m68k/include/asm/ptrace.h @@ -85,6 +85,8 @@ struct switch_stack { #define user_mode(regs) (!((regs)->sr & PS_S)) #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) +#define current_pt_regs() \ + (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1 #define arch_has_single_step() (1) diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 045cfd6a9e31..c702ad716791 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -382,6 +382,8 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_EXECVE +#define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 165ee9f9d5c9..946cb0187751 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -111,6 +111,22 @@ ENTRY(ret_from_fork) addql #4,%sp jra ret_from_exception +ENTRY(ret_from_kernel_thread) + | a3 contains the kernel thread payload, d7 - its argument + movel %d1,%sp@- + jsr schedule_tail + GET_CURRENT(%d0) + movel %d7,(%sp) + jsr %a3@ + addql #4,%sp + movel %d0,(%sp) + jra sys_exit + +ENTRY(ret_from_kernel_execve) + movel 4(%sp), %sp + GET_CURRENT(%d0) + jra ret_from_exception + #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) #ifdef TRAP_DBG_INTERRUPT diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index ac2892e49c7c..c51bb172e14d 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -35,6 +35,7 @@ asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); /* @@ -123,51 +124,6 @@ void show_regs(struct pt_regs * regs) printk("USP: %08lx\n", rdusp()); } -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - mm_segment_t fs; - - fs = get_fs(); - set_fs (KERNEL_DS); - - { - register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; - - retval = __NR_clone; - __asm__ __volatile__ - ("clrl %%d2\n\t" - "trap #0\n\t" /* Linux/m68k system call */ - "tstl %0\n\t" /* child or parent */ - "jne 1f\n\t" /* parent - jump */ -#ifdef CONFIG_MMU - "lea %%sp@(%c7),%6\n\t" /* reload current */ - "movel %6@,%6\n\t" -#endif - "movel %3,%%sp@-\n\t" /* push argument */ - "jsr %4@\n\t" /* call fn */ - "movel %0,%%d1\n\t" /* pass exit value */ - "movel %2,%%d0\n\t" /* exit */ - "trap #0\n" - "1:" - : "+d" (retval) - : "i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), - "i" (-THREAD_SIZE) - : "d2"); - - pid = retval; - } - - set_fs (fs); - return pid; -} -EXPORT_SYMBOL(kernel_thread); - void flush_thread(void) { current->thread.fs = __USER_DS; @@ -219,30 +175,18 @@ asmlinkage int m68k_clone(struct pt_regs *regs) } int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, + unsigned long arg, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long *retp; + struct switch_stack *childstack; childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; p->thread.usp = usp; p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; + p->thread.esp0 = (unsigned long)childregs; /* * Must save the current SFC/DFC value, NOT the value when @@ -250,6 +194,26 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, */ p->thread.fs = get_fs().seg; + if (unlikely(!regs)) { + /* kernel thread */ + memset(childstack, 0, + sizeof(struct switch_stack) + sizeof(struct pt_regs)); + childregs->sr = PS_S; + childstack->a3 = usp; /* function */ + childstack->d7 = arg; + childstack->retpc = (unsigned long)ret_from_kernel_thread; + p->thread.usp = 0; + return 0; + } + *childregs = *regs; + childregs->d0 = 0; + + *childstack = ((struct switch_stack *) regs)[-1]; + childstack->retpc = (unsigned long)ret_from_fork; + + if (clone_flags & CLONE_SETTLS) + task_thread_info(p)->tp_value = regs->d5; + #ifdef CONFIG_FPU if (!FPU_IS_EMU) { /* Copy the current fpu state */ @@ -337,26 +301,6 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) EXPORT_SYMBOL(dump_fpu); #endif /* CONFIG_FPU */ -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - int error; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - unsigned long get_wchan(struct task_struct *p) { unsigned long fp, pc; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 9a5932ec3689..3a480b3df0d6 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -549,23 +549,6 @@ asmlinkage int sys_getpagesize(void) return PAGE_SIZE; } -/* - * Do a system call from kernel instead of calling sys_execve so we - * end up with proper pt_regs. - */ -int kernel_execve(const char *filename, - const char *const argv[], - const char *const envp[]) -{ - register long __res asm ("%d0") = __NR_execve; - register long __a asm ("%d1") = (long)(filename); - register long __b asm ("%d2") = (long)(argv); - register long __c asm ("%d3") = (long)(envp); - asm volatile ("trap #0" : "+d" (__res) - : "d" (__a), "d" (__b), "d" (__c)); - return __res; -} - asmlinkage unsigned long sys_get_thread_area(void) { return current_thread_info()->tp_value; diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h index 6c610234ffab..008f30433d22 100644 --- a/arch/microblaze/include/asm/thread_info.h +++ b/arch/microblaze/include/asm/thread_info.h @@ -121,7 +121,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ /* restore singlestep on return to user mode */ #define TIF_SINGLESTEP 4 -#define TIF_IRET 5 /* return with iret */ #define TIF_MEMDIE 6 /* is terminating due to OOM killer */ #define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ #define TIF_SECCOMP 10 /* secure computing */ @@ -134,7 +133,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) -#define _TIF_IRET (1 << TIF_IRET) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) @@ -184,6 +182,7 @@ static inline bool test_and_clear_restore_sigmask(void) ti->status &= ~TS_RESTORE_SIGMASK; return true; } +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) #endif #endif /* __KERNEL__ */ diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index c1220dbf87cd..3847e5b9c601 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -254,10 +254,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, set_fs(USER_DS); - /* the tracer may want to single-step inside the handler */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - #ifdef DEBUG_SIG printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", current->comm, current->pid, frame, regs->pc); @@ -315,7 +311,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, if (ret) return; - signal_delivered(sig, info, ka, regs, 0); + signal_delivered(sig, info, ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } /* diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index e5b154f24f85..404c0f24bd41 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c @@ -54,13 +54,13 @@ asmlinkage long microblaze_execve(const char __user *filenamei, struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname(filenamei); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); out: return error; diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 946e010f2018..8debe9e91754 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -103,7 +103,6 @@ register struct thread_info *__current_thread_info __asm__("$28"); #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ -#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_FIXADE 20 /* Fix address errors in software */ #define TIF_LOGADE 21 /* Log address errors to syslog */ @@ -125,9 +124,7 @@ register struct thread_info *__current_thread_info __asm__("$28"); #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1<<TIF_SECCOMP) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_USEDFPU (1<<TIF_USEDFPU) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_FIXADE (1<<TIF_FIXADE) #define _TIF_LOGADE (1<<TIF_LOGADE) #define _TIF_32BIT_REGS (1<<TIF_32BIT_REGS) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 922a554cd108..3a21acedf882 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -83,13 +83,13 @@ out: asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs) { int error; - char * filename; + struct filename *filename; filename = getname(compat_ptr(regs.regs[4])); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = compat_do_execve(filename, compat_ptr(regs.regs[5]), + error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]), compat_ptr(regs.regs[6]), ®s); putname(filename); diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index b08220c82113..2bd561bc05ae 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -133,13 +133,13 @@ _sys_clone(nabi_no_regargs struct pt_regs regs) asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs) { int error; - char * filename; + struct filename *filename; filename = getname((const char __user *) (long)regs.regs[4]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *) (long)regs.regs[5], (const char __user *const __user *) (long)regs.regs[6], ®s); diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 5cfb086b3903..ddbdc33471a8 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig @@ -8,6 +8,7 @@ config MN10300 select HAVE_ARCH_KGDB select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER select GENERIC_CLOCKEVENTS + select GENERIC_KERNEL_THREAD config AM33_2 def_bool n diff --git a/arch/mn10300/include/asm/frame.inc b/arch/mn10300/include/asm/frame.inc index 2ee58e3eb6b3..1c3eb4fda958 100644 --- a/arch/mn10300/include/asm/frame.inc +++ b/arch/mn10300/include/asm/frame.inc @@ -61,7 +61,7 @@ ############################################################################### .macro RESTORE_ALL # peel back the stack to the calling frame - # - this permits execve() to discard extra frames due to kernel syscalls + # - we need that when returning from interrupts to kernel mode GET_THREAD_INFO a0 mov (TI_frame,a0),fp mov fp,sp diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h index 247928c9f549..8b80b19d0c8a 100644 --- a/arch/mn10300/include/asm/processor.h +++ b/arch/mn10300/include/asm/processor.h @@ -119,20 +119,13 @@ struct thread_struct { /* * do necessary setup to start up a newly executed thread - * - need to discard the frame stacked by the kernel thread invoking the execve - * syscall (see RESTORE_ALL macro) */ static inline void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned long new_sp) { - struct thread_info *ti = current_thread_info(); - struct pt_regs *frame0; - - frame0 = thread_info_to_uregs(ti); - frame0->epsw = EPSW_nSL | EPSW_IE | EPSW_IM; - frame0->pc = new_pc; - frame0->sp = new_sp; - ti->frame = frame0; + regs->epsw = EPSW_nSL | EPSW_IE | EPSW_IM; + regs->pc = new_pc; + regs->sp = new_sp; } @@ -140,11 +133,6 @@ static inline void start_thread(struct pt_regs *regs, extern void release_thread(struct task_struct *); /* - * create a kernel thread without removing it from tasklists - */ -extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); - -/* * Return saved PC of a blocked thread. */ extern unsigned long thread_saved_pc(struct task_struct *tsk); diff --git a/arch/mn10300/include/asm/ptrace.h b/arch/mn10300/include/asm/ptrace.h index 44251b974f1d..08ac856c053e 100644 --- a/arch/mn10300/include/asm/ptrace.h +++ b/arch/mn10300/include/asm/ptrace.h @@ -86,6 +86,7 @@ struct pt_regs { #define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL) #define instruction_pointer(regs) ((regs)->pc) #define user_stack_pointer(regs) ((regs)->sp) +#define current_pt_regs() current_frame() #define arch_has_single_step() (1) diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h index ac519bbd42ff..f90062b0622d 100644 --- a/arch/mn10300/include/asm/thread_info.h +++ b/arch/mn10300/include/asm/thread_info.h @@ -160,12 +160,13 @@ void arch_release_thread_info(struct thread_info *ti); #define _TIF_SIGPENDING +(1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED +(1 << TIF_NEED_RESCHED) #define _TIF_SINGLESTEP +(1 << TIF_SINGLESTEP) -#define _TIF_RESTORE_SIGMASK +(1 << TIF_RESTORE_SIGMASK) #define _TIF_POLLING_NRFLAG +(1 << TIF_POLLING_NRFLAG) #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 */ +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* __KERNEL__ */ #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/mn10300/include/asm/unistd.h b/arch/mn10300/include/asm/unistd.h index 866eb14749d7..044c770adbb6 100644 --- a/arch/mn10300/include/asm/unistd.h +++ b/arch/mn10300/include/asm/unistd.h @@ -382,6 +382,8 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_EXECVE +#define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile index d06749173d63..561029f7fa44 100644 --- a/arch/mn10300/kernel/Makefile +++ b/arch/mn10300/kernel/Makefile @@ -7,8 +7,8 @@ fpu-obj-y := fpu-nofpu.o fpu-nofpu-low.o fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o obj-y := process.o signal.o entry.o traps.o irq.o \ - ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \ - switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y) \ + ptrace.o setup.o time.o sys_mn10300.o io.o \ + switch_to.o mn10300_ksyms.o $(fpu-obj-y) \ csrc-mn10300.o cevt-mn10300.o obj-$(CONFIG_SMP) += smp.o smp-low.o diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S index 8e11f9f48999..0c631d34c8d7 100644 --- a/arch/mn10300/kernel/entry.S +++ b/arch/mn10300/kernel/entry.S @@ -55,6 +55,20 @@ ENTRY(ret_from_fork) mov d0,(REG_D0,fp) jmp syscall_exit +ENTRY(ret_from_kernel_thread) + call schedule_tail[],0 + mov (REG_D0,fp),d0 + mov (REG_A0,fp),a0 + calls (a0) + jmp sys_exit + +ENTRY(ret_from_kernel_execve) + add -12,d0 /* pt_regs -> frame */ + mov d0,sp + GET_THREAD_INFO a2 + clr d0 + jmp syscall_exit + ############################################################################### # # system call handler @@ -94,6 +108,10 @@ restore_all: ############################################################################### ALIGN syscall_exit_work: + mov (REG_EPSW,fp),d0 + and EPSW_nSL,d0 + beq resume_kernel # returning to supervisor mode + btst _TIF_SYSCALL_TRACE,d2 beq work_pending LOCAL_IRQ_ENABLE # could let syscall_trace_exit() call diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h index 2df440105a80..561785581f6c 100644 --- a/arch/mn10300/kernel/internal.h +++ b/arch/mn10300/kernel/internal.h @@ -15,14 +15,10 @@ struct clocksource; struct clock_event_device; /* - * kthread.S - */ -extern int kernel_thread_helper(int); - -/* * entry.S */ extern void ret_from_fork(struct task_struct *) __attribute__((noreturn)); +extern void ret_from_kernel_thread(struct task_struct *) __attribute__((noreturn)); /* * smp-low.S diff --git a/arch/mn10300/kernel/kernel_execve.S b/arch/mn10300/kernel/kernel_execve.S deleted file mode 100644 index 86039f105268..000000000000 --- a/arch/mn10300/kernel/kernel_execve.S +++ /dev/null @@ -1,37 +0,0 @@ -/* MN10300 In-kernel program execution - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#include <linux/linkage.h> -#include <asm/unistd.h> - -############################################################################### -# -# Do a system call from kernel instead of calling sys_execve so we end up with -# proper pt_regs. -# -# int kernel_execve(const char *filename, char *const argv[], -# char *const envp[]) -# -# On entry: D0/D1/8(SP): arguments to function -# On return: D0: syscall return. -# -############################################################################### - .globl kernel_execve - .type kernel_execve,@function -kernel_execve: - mov a3,a1 - mov d0,a0 - mov (12,sp),a3 - mov +__NR_execve,d0 - syscall 0 - mov a1,a3 - rets - - .size kernel_execve,.-kernel_execve diff --git a/arch/mn10300/kernel/kthread.S b/arch/mn10300/kernel/kthread.S deleted file mode 100644 index b5ae467ac5ec..000000000000 --- a/arch/mn10300/kernel/kthread.S +++ /dev/null @@ -1,31 +0,0 @@ -/* MN10300 Kernel thread trampoline function - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by Mark Salter (msalter@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - .text - -############################################################################### -# -# kernel_thread_helper - trampoline for kernel_thread() -# -# On entry: -# A2 = address of function to call -# D2 = function argument -# -############################################################################### - .globl kernel_thread_helper - .type kernel_thread_helper,@function -kernel_thread_helper: - mov do_exit,d1 - mov d1,(sp) - mov d1,mdr - mov d2,d0 - jmp (a2) - - .size kernel_thread_helper,.-kernel_thread_helper diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index e9cceba193b6..d0c671b6d9ff 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -165,27 +165,6 @@ void show_regs(struct pt_regs *regs) } /* - * create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - - regs.a2 = (unsigned long) fn; - regs.d2 = (unsigned long) arg; - regs.pc = (unsigned long) kernel_thread_helper; - local_save_flags(regs.epsw); - regs.epsw |= EPSW_IE | EPSW_IM_7; - - /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, - NULL, NULL); -} -EXPORT_SYMBOL(kernel_thread); - -/* * free current thread data structures etc.. */ void exit_thread(void) @@ -230,50 +209,42 @@ int copy_thread(unsigned long clone_flags, struct task_struct *p, struct pt_regs *kregs) { struct thread_info *ti = task_thread_info(p); - struct pt_regs *c_uregs, *c_kregs, *uregs; + struct pt_regs *c_regs; unsigned long c_ksp; - uregs = current->thread.uregs; - c_ksp = (unsigned long) task_stack_page(p) + THREAD_SIZE; /* allocate the userspace exception frame and set it up */ c_ksp -= sizeof(struct pt_regs); - c_uregs = (struct pt_regs *) c_ksp; + c_regs = (struct pt_regs *) c_ksp; + c_ksp -= 12; /* allocate function call ABI slack */ - p->thread.uregs = c_uregs; - *c_uregs = *uregs; - c_uregs->sp = c_usp; - c_uregs->epsw &= ~EPSW_FE; /* my FPU */ + /* set up things up so the scheduler can start the new task */ + p->thread.uregs = c_regs; + ti->frame = c_regs; + p->thread.a3 = (unsigned long) c_regs; + p->thread.sp = c_ksp; + p->thread.wchan = p->thread.pc; + p->thread.usp = c_usp; - c_ksp -= 12; /* allocate function call ABI slack */ + if (unlikely(!kregs)) { + memset(c_regs, 0, sizeof(struct pt_regs)); + c_regs->a0 = c_usp; /* function */ + c_regs->d0 = ustk_size; /* argument */ + local_save_flags(c_regs->epsw); + c_regs->epsw |= EPSW_IE | EPSW_IM_7; + p->thread.pc = (unsigned long) ret_from_kernel_thread; + return 0; + } + *c_regs = *kregs; + c_regs->sp = c_usp; + c_regs->epsw &= ~EPSW_FE; /* my FPU */ /* the new TLS pointer is passed in as arg #5 to sys_clone() */ if (clone_flags & CLONE_SETTLS) - c_uregs->e2 = current_frame()->d3; - - /* set up the return kernel frame if called from kernel_thread() */ - c_kregs = c_uregs; - if (kregs != uregs) { - c_ksp -= sizeof(struct pt_regs); - c_kregs = (struct pt_regs *) c_ksp; - *c_kregs = *kregs; - c_kregs->sp = c_usp; - c_kregs->next = c_uregs; -#ifdef CONFIG_MN10300_CURRENT_IN_E2 - c_kregs->e2 = (unsigned long) p; /* current */ -#endif - - c_ksp -= 12; /* allocate function call ABI slack */ - } + c_regs->e2 = current_frame()->d3; - /* set up things up so the scheduler can start the new task */ - ti->frame = c_kregs; - p->thread.a3 = (unsigned long) c_kregs; - p->thread.sp = c_ksp; p->thread.pc = (unsigned long) ret_from_fork; - p->thread.wchan = (unsigned long) ret_from_fork; - p->thread.usp = c_usp; return 0; } @@ -302,22 +273,6 @@ asmlinkage long sys_vfork(void) current_frame(), 0, NULL, NULL); } -asmlinkage long sys_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - char *filename; - int error; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, current_frame()); - putname(filename); - return error; -} - unsigned long get_wchan(struct task_struct *p) { return p->thread.wchan; diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index 4d584ae29ae1..f570b3085ef9 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c @@ -317,10 +317,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, regs->d0 = sig; regs->d1 = (unsigned long) &frame->sc; - /* the tracer may want to single-step inside the handler */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - #if DEBUG_SIG printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", sig, current->comm, current->pid, frame, regs->pc, @@ -398,10 +394,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->d0 = sig; regs->d1 = (long) &frame->info; - /* the tracer may want to single-step inside the handler */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - #if DEBUG_SIG printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", sig, current->comm, current->pid, frame, regs->pc, @@ -475,11 +467,6 @@ 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 */ - if (!user_mode(regs)) - return; - signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { if (handle_signal(signr, &info, &ka, regs) == 0) { diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h index 07a8bc080ef2..07f3212422ad 100644 --- a/arch/openrisc/include/asm/thread_info.h +++ b/arch/openrisc/include/asm/thread_info.h @@ -121,7 +121,6 @@ register struct thread_info *current_thread_info_reg asm("r10"); #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) @@ -129,6 +128,8 @@ register struct thread_info *current_thread_info_reg asm("r10"); /* For OpenRISC, this is anything in the LSW other than syscall trace */ #define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP)) +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* __KERNEL__ */ #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 55210f37d1a3..c35f3ab1a8d3 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -271,7 +271,7 @@ asmlinkage long _sys_execve(const char __user *name, struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname(name); error = PTR_ERR(filename); @@ -279,7 +279,7 @@ asmlinkage long _sys_execve(const char __user *name, if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); out: diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 6785de7bd2a0..a0760b87fd4e 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -34,14 +34,14 @@ int hpux_execve(struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname((const char __user *) regs->gr[26]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *) regs->gr[25], (const char __user *const __user *) regs->gr[24], regs); diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S index 38a1c1b8d4e8..011468857e98 100644 --- a/arch/parisc/hpux/gate.S +++ b/arch/parisc/hpux/gate.S @@ -71,7 +71,7 @@ ENTRY(hpux_gateway_page) STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */ STREG %r27, TASK_PT_GR27(%r1) /* user dp */ STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */ - STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */ + STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */ STREG %r29, TASK_PT_GR29(%r1) /* 8th argument */ STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */ diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h index 22b4726dee49..d1fb79a36f3d 100644 --- a/arch/parisc/include/asm/thread_info.h +++ b/arch/parisc/include/asm/thread_info.h @@ -68,13 +68,16 @@ struct thread_info { #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_32BIT (1 << TIF_32BIT) -#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) #define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP) #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \ _TIF_NEED_RESCHED) +#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ + _TIF_BLOCKSTEP) + +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) #endif /* __KERNEL__ */ diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 8c6b6b6561f0..cbc37216bf90 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -342,13 +342,13 @@ unsigned long thread_saved_pc(struct task_struct *t) asmlinkage int sys_execve(struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname((const char __user *) regs->gr[26]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *) regs->gr[25], (const char __user *const __user *) regs->gr[24], regs); diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 594459bde14e..537996955998 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) (usp - sigframe_size); DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); + regs->orig_r28 = 1; /* no restarts for sigreturn */ + #ifdef CONFIG_64BIT compat_frame = (struct compat_rt_sigframe __user *)frame; @@ -437,7 +439,7 @@ give_sigsegv: * OK, we're invoking a handler. */ -static long +static void handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, struct pt_regs *regs, int in_syscall) { @@ -447,7 +449,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, /* Set up the stack frame */ if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) - return 0; + return; signal_delivered(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP) || @@ -455,13 +457,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", regs->gr[28]); - - return 1; } static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) { + if (regs->orig_r28) + return; + regs->orig_r28 = 1; /* no more restarts */ /* Check the return code */ switch (regs->gr[28]) { case -ERESTART_RESTARTBLOCK: @@ -482,8 +485,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) * we have to do is fiddle the return pointer. */ regs->gr[31] -= 8; /* delayed branching */ - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; break; } } @@ -491,6 +492,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) static inline void insert_restart_trampoline(struct pt_regs *regs) { + if (regs->orig_r28) + return; + regs->orig_r28 = 1; /* no more restarts */ switch(regs->gr[28]) { case -ERESTART_RESTARTBLOCK: { /* Restart the system call - no handlers present */ @@ -525,9 +529,6 @@ insert_restart_trampoline(struct pt_regs *regs) flush_user_icache_range(regs->gr[30], regs->gr[30] + 4); regs->gr[31] = regs->gr[30] + 8; - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - return; } case -ERESTARTNOHAND: @@ -539,9 +540,6 @@ insert_restart_trampoline(struct pt_regs *regs) * slot of the branch external instruction. */ regs->gr[31] -= 8; - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - return; } default: @@ -570,30 +568,17 @@ do_signal(struct pt_regs *regs, long in_syscall) DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n", 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. */ - - /* 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]); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); - if (signr <= 0) - break; - + if (signr > 0) { /* Restart a system call if necessary. */ if (in_syscall) syscall_restart(regs, &ka); - /* 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)) - return; + handle_signal(signr, &info, &ka, regs, in_syscall); + return; } - /* end of while(1) looping forever if we can't force a signal */ /* Did we come from a system call? */ if (in_syscall) diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index dc9a62462323..bf5b93a885d3 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -60,14 +60,14 @@ asmlinkage int sys32_execve(struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26])); filename = getname((const char __user *) regs->gr[26]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = compat_do_execve(filename, compat_ptr(regs->gr[25]), + error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]), compat_ptr(regs->gr[24]), regs); putname(filename); out: diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 82a52b2fb13f..86742df0b194 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -156,7 +156,7 @@ linux_gateway_entry: STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */ STREG %r27, TASK_PT_GR27(%r1) /* user dp */ STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */ - STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */ + STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */ STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */ STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */ @@ -180,9 +180,10 @@ linux_gateway_entry: /* Are we being ptraced? */ mfctl %cr30, %r1 - LDREG TI_TASK(%r1),%r1 - ldw TASK_PTRACE(%r1), %r1 - bb,<,n %r1,31,.Ltracesys + LDREG TI_FLAGS(%r1),%r1 + ldi _TIF_SYSCALL_TRACE_MASK, %r19 + and,COND(=) %r1, %r19, %r0 + b,n .Ltracesys /* Note! We cannot use the syscall table that is mapped nearby since the gateway page is mapped execute-only. */ diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index df7edb887a04..969f3d9ded91 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -137,10 +137,11 @@ config PPC select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_SMP_IDLE_THREAD select GENERIC_CMOS_UPDATE - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL_OLD select GENERIC_CLOCKEVENTS select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER + select GENERIC_KERNEL_THREAD config EARLY_PRINTK bool diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 9dc5cd1fde1a..8734b3855272 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -74,9 +74,6 @@ struct task_struct; void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); void release_thread(struct task_struct *); -/* Create a new kernel thread. */ -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); - /* Lazy FPU handling on uni-processor */ extern struct task_struct *last_task_used_math; extern struct task_struct *last_task_used_altivec; diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 9c21ed42aba6..f76b88c367d1 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -125,6 +125,8 @@ extern unsigned long ptrace_get_reg(struct task_struct *task, int regno); extern int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data); +#define current_pt_regs() \ + ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1) /* * We use the least-significant bit of the trap field to indicate * whether we have saved the full set of registers, or only a diff --git a/arch/powerpc/include/asm/syscalls.h b/arch/powerpc/include/asm/syscalls.h index 4084e567d28e..329db4ec12ca 100644 --- a/arch/powerpc/include/asm/syscalls.h +++ b/arch/powerpc/include/asm/syscalls.h @@ -17,9 +17,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, asmlinkage unsigned long sys_mmap2(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(unsigned long a0, unsigned long a1, - unsigned long a2, unsigned long a3, unsigned long a4, - unsigned long a5, struct pt_regs *regs); asmlinkage int sys_clone(unsigned long clone_flags, unsigned long usp, int __user *parent_tidp, void __user *child_threadptr, int __user *child_tidp, int p6, struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 8ceea14d6fe4..406b7b9a1341 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -182,6 +182,8 @@ static inline bool test_thread_local_flags(unsigned int flags) #define is_32bit_task() (1) #endif +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index c683fa350add..2533752af30f 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -421,6 +421,8 @@ #define __ARCH_WANT_SYS_NEWFSTATAT #define __ARCH_WANT_COMPAT_SYS_SENDFILE #endif +#define __ARCH_WANT_SYS_EXECVE +#define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index af37528da49f..9499385676e7 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -435,6 +435,22 @@ ret_from_fork: li r3,0 b ret_from_syscall + .globl ret_from_kernel_thread +ret_from_kernel_thread: + REST_NVGPRS(r1) + bl schedule_tail + mtlr r14 + mr r3,r15 + PPC440EP_ERR42 + blrl + li r3,0 + b do_exit # no return + + .globl __ret_from_kernel_execve +__ret_from_kernel_execve: + addi r1,r3,-STACK_FRAME_OVERHEAD + b ret_from_syscall + /* Traced system call support */ syscall_dotrace: SAVE_NVGPRS(r1) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 0e931aaffca2..56e0ff0878b5 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -370,6 +370,22 @@ _GLOBAL(ret_from_fork) li r3,0 b syscall_exit +_GLOBAL(ret_from_kernel_thread) + bl .schedule_tail + REST_NVGPRS(r1) + REST_GPR(2,r1) + mtlr r14 + mr r3,r15 + blrl + li r3,0 + b .do_exit # no return + +_GLOBAL(__ret_from_kernel_execve) + addi r1,r3,-STACK_FRAME_OVERHEAD + li r10,1 + std r10,SOFTE(r1) + b syscall_exit + .section ".toc","aw" DSCR_DEFAULT: .tc dscr_default[TC],dscr_default diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index ba16874fe294..7ce26d45777e 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -54,13 +54,6 @@ _GLOBAL(add_reloc_offset) .align 3 2: PPC_LONG 1b -_GLOBAL(kernel_execve) - li r0,__NR_execve - sc - bnslr - neg r3,r3 - blr - _GLOBAL(setjmp) mflr r0 PPC_STL r0,0(r3) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 407e293aad2f..19e096bd0e73 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -663,39 +663,6 @@ _GLOBAL(abs) sub r3,r3,r4 blr -/* - * Create a kernel thread - * kernel_thread(fn, arg, flags) - */ -_GLOBAL(kernel_thread) - stwu r1,-16(r1) - stw r30,8(r1) - stw r31,12(r1) - mr r30,r3 /* function */ - mr r31,r4 /* argument */ - ori r3,r5,CLONE_VM /* flags */ - oris r3,r3,CLONE_UNTRACED>>16 - li r4,0 /* new sp (unused) */ - li r0,__NR_clone - sc - bns+ 1f /* did system call indicate error? */ - neg r3,r3 /* if so, make return code negative */ -1: cmpwi 0,r3,0 /* parent or child? */ - bne 2f /* return if parent */ - li r0,0 /* make top-level stack frame */ - stwu r0,-16(r1) - mtlr r30 /* fn addr in lr */ - mr r3,r31 /* load arg and call fn */ - PPC440EP_ERR42 - blrl - li r0,__NR_exit /* exit if function returns */ - li r3,0 - sc -2: lwz r30,8(r1) - lwz r31,12(r1) - addi r1,r1,16 - blr - #ifdef CONFIG_SMP _GLOBAL(start_secondary_resume) /* Reset stack */ diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 565b78625a32..5cfa8008693b 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -407,40 +407,6 @@ _GLOBAL(scom970_write) /* - * Create a kernel thread - * kernel_thread(fn, arg, flags) - */ -_GLOBAL(kernel_thread) - std r29,-24(r1) - std r30,-16(r1) - stdu r1,-STACK_FRAME_OVERHEAD(r1) - mr r29,r3 - mr r30,r4 - ori r3,r5,CLONE_VM /* flags */ - oris r3,r3,(CLONE_UNTRACED>>16) - li r4,0 /* new sp (unused) */ - li r0,__NR_clone - sc - bns+ 1f /* did system call indicate error? */ - neg r3,r3 /* if so, make return code negative */ -1: cmpdi 0,r3,0 /* parent or child? */ - bne 2f /* return if parent */ - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - ld r2,8(r29) - ld r29,0(r29) - mtlr r29 /* fn addr in lr */ - mr r3,r30 /* load arg and call fn */ - blrl - li r0,__NR_exit /* exit after child exits */ - li r3,0 - sc -2: addi r1,r1,STACK_FRAME_OVERHEAD - ld r29,-24(r1) - ld r30,-16(r1) - blr - -/* * disable_kernel_fp() * Disable the FPU. */ diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 3e4031581c65..19e4288d8486 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -94,7 +94,6 @@ EXPORT_SYMBOL(pci_dram_offset); #endif /* CONFIG_PCI */ EXPORT_SYMBOL(start_thread); -EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(giveup_fpu); #ifdef CONFIG_ALTIVEC diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d5ad666efd8b..ba48233500f6 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -733,30 +733,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, struct task_struct *p, + unsigned long arg, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs, *kregs; extern void ret_from_fork(void); + extern void ret_from_kernel_thread(void); + void (*f)(void); unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; - CHECK_FULL_REGS(regs); /* Copy registers */ sp -= sizeof(struct pt_regs); childregs = (struct pt_regs *) sp; - *childregs = *regs; - if ((childregs->msr & MSR_PR) == 0) { + if (!regs) { /* for kernel thread, set `current' and stackptr in new task */ + memset(childregs, 0, sizeof(struct pt_regs)); childregs->gpr[1] = sp + sizeof(struct pt_regs); -#ifdef CONFIG_PPC32 - childregs->gpr[2] = (unsigned long) p; -#else +#ifdef CONFIG_PPC64 + childregs->gpr[14] = *(unsigned long *)usp; + childregs->gpr[2] = ((unsigned long *)usp)[1], clear_tsk_thread_flag(p, TIF_32BIT); +#else + childregs->gpr[14] = usp; /* function */ + childregs->gpr[2] = (unsigned long) p; #endif + childregs->gpr[15] = arg; p->thread.regs = NULL; /* no user register state */ + f = ret_from_kernel_thread; } else { + CHECK_FULL_REGS(regs); + *childregs = *regs; childregs->gpr[1] = usp; p->thread.regs = childregs; + childregs->gpr[3] = 0; /* Result from fork() */ if (clone_flags & CLONE_SETTLS) { #ifdef CONFIG_PPC64 if (!is_32bit_task()) @@ -765,8 +774,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, #endif childregs->gpr[2] = childregs->gpr[6]; } + + f = ret_from_fork; } - childregs->gpr[3] = 0; /* Result from fork() */ sp -= STACK_FRAME_OVERHEAD; /* @@ -805,19 +815,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.dscr = current->thread.dscr; } #endif - /* * The PPC64 ABI makes use of a TOC to contain function * pointers. The function (ret_from_except) is actually a pointer * to the TOC entry. The first entry is a pointer to the actual * function. - */ + */ #ifdef CONFIG_PPC64 - kregs->nip = *((unsigned long *)ret_from_fork); + kregs->nip = *((unsigned long *)f); #else - kregs->nip = (unsigned long)ret_from_fork; + kregs->nip = (unsigned long)f; #endif - return 0; } @@ -1055,26 +1063,13 @@ int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, regs, 0, NULL, NULL); } -int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) +void __ret_from_kernel_execve(struct pt_regs *normal) +__noreturn; + +void ret_from_kernel_execve(struct pt_regs *normal) { - int error; - char *filename; - - filename = getname((const char __user *) a0); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - flush_spe_to_thread(current); - error = do_execve(filename, - (const char __user *const __user *) a1, - (const char __user *const __user *) a2, regs); - putname(filename); -out: - return error; + set_thread_flag(TIF_RESTOREALL); + __ret_from_kernel_execve(normal); } static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 8b4c049aee20..804e323c139d 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -35,7 +35,6 @@ #include <linux/stddef.h> #include <linux/tty.h> #include <linux/binfmts.h> -#include <linux/freezer.h> #endif #include <asm/uaccess.h> diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index abd1112da54f..9c2ed90ece8f 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -156,28 +156,6 @@ asmlinkage long compat_sys_sendfile64_wrapper(u32 out_fd, u32 in_fd, (off_t __user *)offset, count); } -long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) -{ - int error; - char * filename; - - filename = getname((char __user *) a0); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - - error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs); - - putname(filename); - -out: - return error; -} - /* Note: it is necessary to treat option as an unsigned int, * with the corresponding cast to a signed int to insure that the * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index c9986fd400d8..ce4cb772dc78 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -73,7 +73,7 @@ /* powerpc clocksource/clockevent code */ #include <linux/clockchips.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> static cycle_t rtc_read(struct clocksource *); static struct clocksource clocksource_rtc = { @@ -727,7 +727,7 @@ static cycle_t timebase_read(struct clocksource *cs) return (cycle_t)get_tb(); } -void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, +void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, struct clocksource *clock, u32 mult) { u64 new_tb_to_xs, new_stamp_xsec; diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 51faaac8abe6..185bedd926df 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -23,6 +23,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/kthread.h> #include <asm/eeh_event.h> #include <asm/ppc-pci.h> @@ -59,8 +60,6 @@ static int eeh_event_handler(void * dummy) struct eeh_event *event; struct eeh_pe *pe; - set_task_comm(current, "eehd"); - spin_lock_irqsave(&eeh_eventlist_lock, flags); event = NULL; @@ -108,7 +107,7 @@ static int eeh_event_handler(void * dummy) */ static void eeh_thread_launcher(struct work_struct *dummy) { - if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0) + if (IS_ERR(kthread_run(eeh_event_handler, NULL, "eehd"))) printk(KERN_ERR "Failed to start EEH daemon\n"); } diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index dc0a035e63bb..ecdb0a6b3171 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -77,8 +77,9 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz { unsigned long start, start_pfn; struct zone *zone; - int i, ret; - int sections_to_remove; + int ret; + unsigned long section; + unsigned long sections_to_remove; start_pfn = base >> PAGE_SHIFT; @@ -99,9 +100,9 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz * while writing to it. So we have to defer it to here. */ sections_to_remove = (memblock_size >> PAGE_SHIFT) / PAGES_PER_SECTION; - for (i = 0; i < sections_to_remove; i++) { - unsigned long pfn = start_pfn + i * PAGES_PER_SECTION; - ret = __remove_pages(zone, start_pfn, PAGES_PER_SECTION); + for (section = 0; section < sections_to_remove; section++) { + unsigned long pfn = start_pfn + section * PAGES_PER_SECTION; + ret = __remove_pages(zone, pfn, PAGES_PER_SECTION); if (ret) return ret; } diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 99d2d790d152..e5dac1236185 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -131,7 +131,7 @@ config S390 select HAVE_UID16 if 32BIT select ARCH_WANT_IPC_PARSE_VERSION select GENERIC_SMP_IDLE_THREAD - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL_OLD select GENERIC_CLOCKEVENTS select KTIME_SCALAR if 32BIT select HAVE_ARCH_SECCOMP_FILTER diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index bb08e2afc5de..9e2cfe0349c3 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -91,8 +91,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ #define TIF_SECCOMP 10 /* secure computing */ #define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */ -#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling - TIF_NEED_RESCHED */ #define TIF_31BIT 17 /* 32bit process */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 19 /* restore signal mask in do_signal() */ @@ -100,7 +98,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL (1<<TIF_SYSCALL) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_PER_TRAP (1<<TIF_PER_TRAP) @@ -109,7 +106,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1<<TIF_SECCOMP) #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_31BIT (1<<TIF_31BIT) #define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 2db1011b8b19..7fcd690d42c7 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -34,7 +34,7 @@ #include <linux/profile.h> #include <linux/timex.h> #include <linux/notifier.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/clockchips.h> #include <linux/gfp.h> #include <linux/kprobes.h> @@ -219,7 +219,7 @@ struct clocksource * __init clocksource_default_clock(void) return &clocksource_tod; } -void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, +void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, struct clocksource *clock, u32 mult) { if (clock != &clocksource_tod) diff --git a/arch/score/include/asm/thread_info.h b/arch/score/include/asm/thread_info.h index a18006e97f1c..1425cc034872 100644 --- a/arch/score/include/asm/thread_info.h +++ b/arch/score/include/asm/thread_info.h @@ -86,16 +86,12 @@ register struct thread_info *__current_thread_info __asm__("r28"); #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ -#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling - TIF_NEED_RESCHED */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_WORK_MASK (0x0000ffff) diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index e382c52ca0d9..c268bbf8b410 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c @@ -174,6 +174,7 @@ score_rt_sigreturn(struct pt_regs *regs) /* It is more difficult to avoid calling this function than to call it and ignore errors. */ do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]); + regs->is_syscall = 0; __asm__ __volatile__( "mv\tr0, %0\n\t" diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index 21e867974066..d45cf00a3351 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c @@ -92,14 +92,14 @@ asmlinkage long score_execve(struct pt_regs *regs) { int error; - char *filename; + struct filename *filename; filename = getname((char __user*)regs->regs[4]); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *)regs->regs[5], (const char __user *const __user *)regs->regs[6], regs); diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index bc13b57cdc83..7d5ac4e48485 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -206,6 +206,9 @@ static inline bool test_and_clear_restore_sigmask(void) ti->status &= ~TS_RESTORE_SIGMASK; return true; } + +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 59521e8a164d..ba7345f37bc9 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -298,14 +298,14 @@ asmlinkage int sys_execve(const char __user *ufilename, { struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int error; - char *filename; + struct filename *filename; filename = getname(ufilename); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, uargv, uenvp, regs); + error = do_execve(filename->name, uargv, uenvp, regs); putname(filename); out: return error; diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 602545b12a86..98a709f0c3c4 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -491,14 +491,14 @@ asmlinkage int sys_execve(const char *ufilename, char **uargv, struct pt_regs *pregs) { int error; - char *filename; + struct filename *filename; filename = getname((char __user *)ufilename); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *)uargv, (const char __user *const __user *)uenvp, pregs); diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index d6b7b6154f87..2f1f65356c0c 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -22,7 +22,6 @@ #include <linux/elf.h> #include <linux/personality.h> #include <linux/binfmts.h> -#include <linux/freezer.h> #include <linux/io.h> #include <linux/tracehook.h> #include <asm/ucontext.h> diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 6b5b3dfe886b..23853814bd17 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -18,7 +18,6 @@ #include <linux/errno.h> #include <linux/wait.h> #include <linux/personality.h> -#include <linux/freezer.h> #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/stddef.h> diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h index e6cd224506a9..25849ae3e900 100644 --- a/arch/sparc/include/asm/thread_info_32.h +++ b/arch/sparc/include/asm/thread_info_32.h @@ -126,13 +126,14 @@ register struct thread_info *current_thread_info_reg asm("g6"); #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_USEDFPU (1<<TIF_USEDFPU) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | \ _TIF_SIGPENDING) +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* __KERNEL__ */ #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index cfa8c38fb9c8..4e2276631081 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h @@ -256,6 +256,9 @@ static inline bool test_and_clear_restore_sigmask(void) ti->status &= ~TS_RESTORE_SIGMASK; return true; } + +#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index 7c831d848b4e..73083e1d38d9 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -265,6 +265,11 @@ extern __must_check long strnlen_user(const char __user *str, long n); #define __copy_to_user_inatomic ___copy_to_user #define __copy_from_user_inatomic ___copy_from_user +struct pt_regs; +extern unsigned long compute_effective_address(struct pt_regs *, + unsigned int insn, + unsigned int rd); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_UACCESS_H */ diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 14006d8aca28..487bffb36f5e 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -482,7 +482,7 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) asmlinkage int sparc_execve(struct pt_regs *regs) { int error, base = 0; - char *filename; + struct filename *filename; /* Check for indirect call. */ if(regs->u_regs[UREG_G1] == 0) @@ -492,7 +492,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs) error = PTR_ERR(filename); if(IS_ERR(filename)) goto out; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *) regs->u_regs[base + UREG_I1], (const char __user *const __user *) diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index aff0c72fac09..fcaa59421126 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -722,7 +722,7 @@ EXPORT_SYMBOL(dump_fpu); asmlinkage int sparc_execve(struct pt_regs *regs) { int error, base = 0; - char *filename; + struct filename *filename; /* User register window flush is done by entry.S */ @@ -734,7 +734,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs) error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, + error = do_execve(filename->name, (const char __user *const __user *) regs->u_regs[base + UREG_I1], (const char __user *const __user *) diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index d862499eb01c..c3239811a1b5 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c @@ -403,7 +403,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig, asmlinkage long sparc32_execve(struct pt_regs *regs) { int error, base = 0; - char *filename; + struct filename *filename; /* User register window flush is done by entry.S */ @@ -416,7 +416,7 @@ asmlinkage long sparc32_execve(struct pt_regs *regs) if (IS_ERR(filename)) goto out; - error = compat_do_execve(filename, + error = compat_do_execve(filename->name, compat_ptr(regs->u_regs[base + UREG_I1]), compat_ptr(regs->u_regs[base + UREG_I2]), regs); diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index 1d7e274f3f2b..7f5f65d0b3fd 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -212,24 +212,20 @@ linux_sparc_syscall: 3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] ret_sys_call: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 - ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc sra %o0, 0, %o0 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 sllx %g2, 32, %g2 - /* Check if force_successful_syscall_return() - * was invoked. - */ - ldub [%g6 + TI_SYS_NOERROR], %l2 - brnz,a,pn %l2, 80f - stb %g0, [%g6 + TI_SYS_NOERROR] - cmp %o0, -ERESTART_RESTARTBLOCK bgeu,pn %xcc, 1f - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %l6 -80: + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0 + ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc + +2: + stb %g0, [%g6 + TI_SYS_NOERROR] /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 +3: stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] bne,pn %icc, linux_syscall_trace2 add %l1, 0x4, %l2 ! npc = npc+4 @@ -238,20 +234,20 @@ ret_sys_call: stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] 1: + /* Check if force_successful_syscall_return() + * was invoked. + */ + ldub [%g6 + TI_SYS_NOERROR], %l2 + brnz,pn %l2, 2b + ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc /* System call failure, set Carry condition code. * Also, get abs(errno) to return to the process. */ - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %l6 sub %g0, %o0, %o0 - or %g3, %g2, %g3 stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] - stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] - bne,pn %icc, linux_syscall_trace2 - add %l1, 0x4, %l2 ! npc = npc+4 - stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] + ba,pt %xcc, 3b + or %g3, %g2, %g3 - b,pt %xcc, rtrap - stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] linux_syscall_trace2: call syscall_trace_leave add %sp, PTREGS_OFF, %o0 diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index fa1f1d375ffc..b66a77968f35 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -1,6 +1,6 @@ /* arch/sparc64/kernel/traps.c * - * Copyright (C) 1995,1997,2008,2009 David S. Miller (davem@davemloft.net) + * Copyright (C) 1995,1997,2008,2009,2012 David S. Miller (davem@davemloft.net) * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com) */ @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/kdebug.h> #include <linux/ftrace.h> +#include <linux/reboot.h> #include <linux/gfp.h> #include <asm/smp.h> @@ -1760,85 +1761,223 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs) } struct sun4v_error_entry { - u64 err_handle; - u64 err_stick; + /* Unique error handle */ +/*0x00*/u64 err_handle; - u32 err_type; + /* %stick value at the time of the error */ +/*0x08*/u64 err_stick; + +/*0x10*/u8 reserved_1[3]; + + /* Error type */ +/*0x13*/u8 err_type; #define SUN4V_ERR_TYPE_UNDEFINED 0 #define SUN4V_ERR_TYPE_UNCORRECTED_RES 1 #define SUN4V_ERR_TYPE_PRECISE_NONRES 2 #define SUN4V_ERR_TYPE_DEFERRED_NONRES 3 -#define SUN4V_ERR_TYPE_WARNING_RES 4 +#define SUN4V_ERR_TYPE_SHUTDOWN_RQST 4 +#define SUN4V_ERR_TYPE_DUMP_CORE 5 +#define SUN4V_ERR_TYPE_SP_STATE_CHANGE 6 +#define SUN4V_ERR_TYPE_NUM 7 - u32 err_attrs; + /* Error attributes */ +/*0x14*/u32 err_attrs; #define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001 #define SUN4V_ERR_ATTRS_MEMORY 0x00000002 #define SUN4V_ERR_ATTRS_PIO 0x00000004 #define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008 #define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010 -#define SUN4V_ERR_ATTRS_USER_MODE 0x01000000 -#define SUN4V_ERR_ATTRS_PRIV_MODE 0x02000000 +#define SUN4V_ERR_ATTRS_SHUTDOWN_RQST 0x00000020 +#define SUN4V_ERR_ATTRS_ASR 0x00000040 +#define SUN4V_ERR_ATTRS_ASI 0x00000080 +#define SUN4V_ERR_ATTRS_PRIV_REG 0x00000100 +#define SUN4V_ERR_ATTRS_SPSTATE_MSK 0x00000600 +#define SUN4V_ERR_ATTRS_SPSTATE_SHFT 9 +#define SUN4V_ERR_ATTRS_MODE_MSK 0x03000000 +#define SUN4V_ERR_ATTRS_MODE_SHFT 24 #define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000 - u64 err_raddr; - u32 err_size; - u16 err_cpu; - u16 err_pad; +#define SUN4V_ERR_SPSTATE_FAULTED 0 +#define SUN4V_ERR_SPSTATE_AVAILABLE 1 +#define SUN4V_ERR_SPSTATE_NOT_PRESENT 2 + +#define SUN4V_ERR_MODE_USER 1 +#define SUN4V_ERR_MODE_PRIV 2 + + /* Real address of the memory region or PIO transaction */ +/*0x18*/u64 err_raddr; + + /* Size of the operation triggering the error, in bytes */ +/*0x20*/u32 err_size; + + /* ID of the CPU */ +/*0x24*/u16 err_cpu; + + /* Grace periof for shutdown, in seconds */ +/*0x26*/u16 err_secs; + + /* Value of the %asi register */ +/*0x28*/u8 err_asi; + +/*0x29*/u8 reserved_2; + + /* Value of the ASR register number */ +/*0x2a*/u16 err_asr; +#define SUN4V_ERR_ASR_VALID 0x8000 + +/*0x2c*/u32 reserved_3; +/*0x30*/u64 reserved_4; +/*0x38*/u64 reserved_5; }; static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0); static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0); -static const char *sun4v_err_type_to_str(u32 type) -{ - switch (type) { - case SUN4V_ERR_TYPE_UNDEFINED: - return "undefined"; - case SUN4V_ERR_TYPE_UNCORRECTED_RES: - return "uncorrected resumable"; - case SUN4V_ERR_TYPE_PRECISE_NONRES: - return "precise nonresumable"; - case SUN4V_ERR_TYPE_DEFERRED_NONRES: - return "deferred nonresumable"; - case SUN4V_ERR_TYPE_WARNING_RES: - return "warning resumable"; - default: - return "unknown"; +static const char *sun4v_err_type_to_str(u8 type) +{ + static const char *types[SUN4V_ERR_TYPE_NUM] = { + "undefined", + "uncorrected resumable", + "precise nonresumable", + "deferred nonresumable", + "shutdown request", + "dump core", + "SP state change", + }; + + if (type < SUN4V_ERR_TYPE_NUM) + return types[type]; + + return "unknown"; +} + +static void sun4v_emit_err_attr_strings(u32 attrs) +{ + static const char *attr_names[] = { + "processor", + "memory", + "PIO", + "int-registers", + "fpu-registers", + "shutdown-request", + "ASR", + "ASI", + "priv-reg", + }; + static const char *sp_states[] = { + "sp-faulted", + "sp-available", + "sp-not-present", + "sp-state-reserved", + }; + static const char *modes[] = { + "mode-reserved0", + "user", + "priv", + "mode-reserved1", + }; + u32 sp_state, mode; + int i; + + for (i = 0; i < ARRAY_SIZE(attr_names); i++) { + if (attrs & (1U << i)) { + const char *s = attr_names[i]; + + pr_cont("%s ", s); + } } + + sp_state = ((attrs & SUN4V_ERR_ATTRS_SPSTATE_MSK) >> + SUN4V_ERR_ATTRS_SPSTATE_SHFT); + pr_cont("%s ", sp_states[sp_state]); + + mode = ((attrs & SUN4V_ERR_ATTRS_MODE_MSK) >> + SUN4V_ERR_ATTRS_MODE_SHFT); + pr_cont("%s ", modes[mode]); + + if (attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) + pr_cont("res-queue-full "); } -static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt) +/* When the report contains a real-address of "-1" it means that the + * hardware did not provide the address. So we compute the effective + * address of the load or store instruction at regs->tpc and report + * that. Usually when this happens it's a PIO and in such a case we + * are using physical addresses with bypass ASIs anyways, so what we + * report here is exactly what we want. + */ +static void sun4v_report_real_raddr(const char *pfx, struct pt_regs *regs) { + unsigned int insn; + u64 addr; + + if (!(regs->tstate & TSTATE_PRIV)) + return; + + insn = *(unsigned int *) regs->tpc; + + addr = compute_effective_address(regs, insn, 0); + + printk("%s: insn effective address [0x%016llx]\n", + pfx, addr); +} + +static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, + int cpu, const char *pfx, atomic_t *ocnt) +{ + u64 *raw_ptr = (u64 *) ent; + u32 attrs; int cnt; printk("%s: Reporting on cpu %d\n", pfx, cpu); - printk("%s: err_handle[%llx] err_stick[%llx] err_type[%08x:%s]\n", - pfx, - ent->err_handle, ent->err_stick, - ent->err_type, - sun4v_err_type_to_str(ent->err_type)); - printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n", - pfx, - ent->err_attrs, - ((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ? - "processor" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ? - "memory" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ? - "pio" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ? - "integer-regs" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ? - "fpu-regs" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ? - "user" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ? - "privileged" : ""), - ((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ? - "queue-full" : "")); - printk("%s: err_raddr[%016llx] err_size[%u] err_cpu[%u]\n", - pfx, - ent->err_raddr, ent->err_size, ent->err_cpu); + printk("%s: TPC [0x%016lx] <%pS>\n", + pfx, regs->tpc, (void *) regs->tpc); + + printk("%s: RAW [%016llx:%016llx:%016llx:%016llx\n", + pfx, raw_ptr[0], raw_ptr[1], raw_ptr[2], raw_ptr[3]); + printk("%s: %016llx:%016llx:%016llx:%016llx]\n", + pfx, raw_ptr[4], raw_ptr[5], raw_ptr[6], raw_ptr[7]); + + printk("%s: handle [0x%016llx] stick [0x%016llx]\n", + pfx, ent->err_handle, ent->err_stick); + + printk("%s: type [%s]\n", pfx, sun4v_err_type_to_str(ent->err_type)); + + attrs = ent->err_attrs; + printk("%s: attrs [0x%08x] < ", pfx, attrs); + sun4v_emit_err_attr_strings(attrs); + pr_cont(">\n"); + + /* Various fields in the error report are only valid if + * certain attribute bits are set. + */ + if (attrs & (SUN4V_ERR_ATTRS_MEMORY | + SUN4V_ERR_ATTRS_PIO | + SUN4V_ERR_ATTRS_ASI)) { + printk("%s: raddr [0x%016llx]\n", pfx, ent->err_raddr); + + if (ent->err_raddr == ~(u64)0) + sun4v_report_real_raddr(pfx, regs); + } + + if (attrs & (SUN4V_ERR_ATTRS_MEMORY | SUN4V_ERR_ATTRS_ASI)) + printk("%s: size [0x%x]\n", pfx, ent->err_size); + + if (attrs & (SUN4V_ERR_ATTRS_PROCESSOR | + SUN4V_ERR_ATTRS_INT_REGISTERS | + SUN4V_ERR_ATTRS_FPU_REGISTERS | + SUN4V_ERR_ATTRS_PRIV_REG)) + printk("%s: cpu[%u]\n", pfx, ent->err_cpu); + + if (attrs & SUN4V_ERR_ATTRS_ASI) + printk("%s: asi [0x%02x]\n", pfx, ent->err_asi); + + if ((attrs & (SUN4V_ERR_ATTRS_INT_REGISTERS | + SUN4V_ERR_ATTRS_FPU_REGISTERS | + SUN4V_ERR_ATTRS_PRIV_REG)) && + (ent->err_asr & SUN4V_ERR_ASR_VALID) != 0) + printk("%s: reg [0x%04x]\n", + pfx, ent->err_asr & ~SUN4V_ERR_ASR_VALID); show_regs(regs); @@ -1874,13 +2013,15 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset) put_cpu(); - if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) { - /* If err_type is 0x4, it's a powerdown request. Do - * not do the usual resumable error log because that - * makes it look like some abnormal error. + if (local_copy.err_type == SUN4V_ERR_TYPE_SHUTDOWN_RQST) { + /* We should really take the seconds field of + * the error report and use it for the shutdown + * invocation, but for now do the same thing we + * do for a DS shutdown request. */ - printk(KERN_INFO "Power down request...\n"); - kill_cad_pid(SIGINT, 1); + pr_info("Shutdown request, %u seconds...\n", + local_copy.err_secs); + orderly_poweroff(true); return; } diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 2976dba1ebaf..097aee763af3 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -151,8 +151,6 @@ show_signal_msg(struct pt_regs *regs, int sig, int code, printk(KERN_CONT "\n"); } -extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int); - static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, unsigned int insn, int fault_code) { diff --git a/arch/tile/include/arch/Kbuild b/arch/tile/include/arch/Kbuild index 9c0ea24cc948..e69de29bb2d1 100644 --- a/arch/tile/include/arch/Kbuild +++ b/arch/tile/include/arch/Kbuild @@ -1,17 +0,0 @@ -header-y += abi.h -header-y += chip.h -header-y += chip_tile64.h -header-y += chip_tilegx.h -header-y += chip_tilepro.h -header-y += icache.h -header-y += interrupts.h -header-y += interrupts_32.h -header-y += interrupts_64.h -header-y += opcode.h -header-y += opcode_tilegx.h -header-y += opcode_tilepro.h -header-y += sim.h -header-y += sim_def.h -header-y += spr_def.h -header-y += spr_def_32.h -header-y += spr_def_64.h diff --git a/arch/tile/include/arch/spr_def.h b/arch/tile/include/arch/spr_def.h index d6ba449b5363..2de83e7aff3e 100644 --- a/arch/tile/include/arch/spr_def.h +++ b/arch/tile/include/arch/spr_def.h @@ -11,15 +11,11 @@ * NON INFRINGEMENT. See the GNU General Public License for * more details. */ +#ifndef __ARCH_SPR_DEF_H__ +#define __ARCH_SPR_DEF_H__ -/* Include the proper base SPR definition file. */ -#ifdef __tilegx__ -#include <arch/spr_def_64.h> -#else -#include <arch/spr_def_32.h> -#endif +#include <uapi/arch/spr_def.h> -#ifdef __KERNEL__ /* * In addition to including the proper base SPR definition file, depending @@ -110,4 +106,4 @@ #define INT_INTCTRL_K \ _concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,) -#endif /* __KERNEL__ */ +#endif /* __ARCH_SPR_DEF_H__ */ diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild index 5cd98fac9899..c68808a09da7 100644 --- a/arch/tile/include/asm/Kbuild +++ b/arch/tile/include/asm/Kbuild @@ -1,10 +1,7 @@ -include include/asm-generic/Kbuild.asm header-y += ../arch/ -header-y += cachectl.h header-y += ucontext.h -header-y += hardwall.h generic-y += bug.h generic-y += bugs.h diff --git a/arch/tile/include/asm/hardwall.h b/arch/tile/include/asm/hardwall.h index 47514a58d685..2f572b6b7bc2 100644 --- a/arch/tile/include/asm/hardwall.h +++ b/arch/tile/include/asm/hardwall.h @@ -14,40 +14,11 @@ * Provide methods for access control of per-cpu resources like * UDN, IDN, or IPI. */ - #ifndef _ASM_TILE_HARDWALL_H #define _ASM_TILE_HARDWALL_H -#include <arch/chip.h> -#include <linux/ioctl.h> - -#define HARDWALL_IOCTL_BASE 0xa2 - -/* - * The HARDWALL_CREATE() ioctl is a macro with a "size" argument. - * The resulting ioctl value is passed to the kernel in conjunction - * with a pointer to a standard kernel bitmask of cpus. - * For network resources (UDN or IDN) the bitmask must physically - * represent a rectangular configuration on the chip. - * The "size" is the number of bytes of cpu mask data. - */ -#define _HARDWALL_CREATE 1 -#define HARDWALL_CREATE(size) \ - _IOC(_IOC_READ, HARDWALL_IOCTL_BASE, _HARDWALL_CREATE, (size)) - -#define _HARDWALL_ACTIVATE 2 -#define HARDWALL_ACTIVATE \ - _IO(HARDWALL_IOCTL_BASE, _HARDWALL_ACTIVATE) - -#define _HARDWALL_DEACTIVATE 3 -#define HARDWALL_DEACTIVATE \ - _IO(HARDWALL_IOCTL_BASE, _HARDWALL_DEACTIVATE) - -#define _HARDWALL_GET_ID 4 -#define HARDWALL_GET_ID \ - _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID) +#include <uapi/asm/hardwall.h> -#ifdef __KERNEL__ /* /proc hooks for hardwall. */ struct proc_dir_entry; #ifdef CONFIG_HARDWALL @@ -56,6 +27,4 @@ int proc_pid_hardwall(struct task_struct *task, char *buffer); #else static inline void proc_tile_hardwall_init(struct proc_dir_entry *root) {} #endif -#endif - #endif /* _ASM_TILE_HARDWALL_H */ diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h index c6cddd7e8d51..1a4fd9ab0ee1 100644 --- a/arch/tile/include/asm/ptrace.h +++ b/arch/tile/include/asm/ptrace.h @@ -11,87 +11,21 @@ * NON INFRINGEMENT. See the GNU General Public License for * more details. */ - #ifndef _ASM_TILE_PTRACE_H #define _ASM_TILE_PTRACE_H -#include <arch/chip.h> -#include <arch/abi.h> - -/* These must match struct pt_regs, below. */ -#if CHIP_WORD_SIZE() == 32 -#define PTREGS_OFFSET_REG(n) ((n)*4) -#else -#define PTREGS_OFFSET_REG(n) ((n)*8) -#endif -#define PTREGS_OFFSET_BASE 0 -#define PTREGS_OFFSET_TP PTREGS_OFFSET_REG(53) -#define PTREGS_OFFSET_SP PTREGS_OFFSET_REG(54) -#define PTREGS_OFFSET_LR PTREGS_OFFSET_REG(55) -#define PTREGS_NR_GPRS 56 -#define PTREGS_OFFSET_PC PTREGS_OFFSET_REG(56) -#define PTREGS_OFFSET_EX1 PTREGS_OFFSET_REG(57) -#define PTREGS_OFFSET_FAULTNUM PTREGS_OFFSET_REG(58) -#define PTREGS_OFFSET_ORIG_R0 PTREGS_OFFSET_REG(59) -#define PTREGS_OFFSET_FLAGS PTREGS_OFFSET_REG(60) -#if CHIP_HAS_CMPEXCH() -#define PTREGS_OFFSET_CMPEXCH PTREGS_OFFSET_REG(61) -#endif -#define PTREGS_SIZE PTREGS_OFFSET_REG(64) +#include <linux/compiler.h> #ifndef __ASSEMBLY__ - -#ifdef __KERNEL__ /* Benefit from consistent use of "long" on all chips. */ typedef unsigned long pt_reg_t; -#else -/* Provide appropriate length type to userspace regardless of -m32/-m64. */ -typedef uint_reg_t pt_reg_t; -#endif - -/* - * This struct defines the way the registers are stored on the stack during a - * system call or exception. "struct sigcontext" has the same shape. - */ -struct pt_regs { - /* Saved main processor registers; 56..63 are special. */ - /* tp, sp, and lr must immediately follow regs[] for aliasing. */ - pt_reg_t regs[53]; - pt_reg_t tp; /* aliases regs[TREG_TP] */ - pt_reg_t sp; /* aliases regs[TREG_SP] */ - pt_reg_t lr; /* aliases regs[TREG_LR] */ - - /* Saved special registers. */ - pt_reg_t pc; /* stored in EX_CONTEXT_K_0 */ - pt_reg_t ex1; /* stored in EX_CONTEXT_K_1 (PL and ICS bit) */ - pt_reg_t faultnum; /* fault number (INT_SWINT_1 for syscall) */ - pt_reg_t orig_r0; /* r0 at syscall entry, else zero */ - pt_reg_t flags; /* flags (see below) */ -#if !CHIP_HAS_CMPEXCH() - pt_reg_t pad[3]; -#else - pt_reg_t cmpexch; /* value of CMPEXCH_VALUE SPR at interrupt */ - pt_reg_t pad[2]; #endif -}; - -#endif /* __ASSEMBLY__ */ -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 -#define PTRACE_GETFPREGS 14 -#define PTRACE_SETFPREGS 15 +#include <uapi/asm/ptrace.h> -/* Support TILE-specific ptrace options, with events starting at 16. */ -#define PTRACE_O_TRACEMIGRATE 0x00010000 -#define PTRACE_EVENT_MIGRATE 16 -#ifdef __KERNEL__ #define PTRACE_O_MASK_TILE (PTRACE_O_TRACEMIGRATE) #define PT_TRACE_MIGRATE 0x00080000 #define PT_TRACE_MASK_TILE (PT_TRACE_MIGRATE) -#endif - -#ifdef __KERNEL__ /* Flag bits in pt_regs.flags */ #define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ @@ -159,6 +93,4 @@ extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, #define SINGLESTEP_STATE_TARGET_LB 2 #define SINGLESTEP_STATE_TARGET_UB 7 -#endif /* !__KERNEL__ */ - #endif /* _ASM_TILE_PTRACE_H */ diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h index c67eb70ea78e..d048888c5d9a 100644 --- a/arch/tile/include/asm/setup.h +++ b/arch/tile/include/asm/setup.h @@ -11,16 +11,13 @@ * NON INFRINGEMENT. See the GNU General Public License for * more details. */ - #ifndef _ASM_TILE_SETUP_H #define _ASM_TILE_SETUP_H -#define COMMAND_LINE_SIZE 2048 - -#ifdef __KERNEL__ #include <linux/pfn.h> #include <linux/init.h> +#include <uapi/asm/setup.h> /* * Reserved space for vmalloc and iomap - defined in asm/page.h @@ -53,6 +50,4 @@ int hardwall_ipi_valid(int cpu); } while (0) #endif -#endif /* __KERNEL__ */ - #endif /* _ASM_TILE_SETUP_H */ diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h index 1e5e49aad548..10e183de96d3 100644 --- a/arch/tile/include/asm/signal.h +++ b/arch/tile/include/asm/signal.h @@ -11,19 +11,11 @@ * NON INFRINGEMENT. See the GNU General Public License for * more details. */ - #ifndef _ASM_TILE_SIGNAL_H #define _ASM_TILE_SIGNAL_H -/* Do not notify a ptracer when this signal is handled. */ -#define SA_NOPTRACE 0x02000000u - -/* Used in earlier Tilera releases, so keeping for binary compatibility. */ -#define SA_RESTORER 0x04000000u - -#include <asm-generic/signal.h> +#include <uapi/asm/signal.h> -#if defined(__KERNEL__) #if !defined(__ASSEMBLY__) struct pt_regs; int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); @@ -34,6 +26,4 @@ void signal_fault(const char *type, struct pt_regs *, void trace_unhandled_signal(const char *type, struct pt_regs *regs, unsigned long address, int signo); #endif -#endif - #endif /* _ASM_TILE_SIGNAL_H */ diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h index 0e1f3e66e492..6e032a0a268e 100644 --- a/arch/tile/include/asm/unistd.h +++ b/arch/tile/include/asm/unistd.h @@ -11,32 +11,9 @@ * NON INFRINGEMENT. See the GNU General Public License for * more details. */ - -#if !defined(__LP64__) || defined(__SYSCALL_COMPAT) -/* Use the flavor of this syscall that matches the 32-bit API better. */ -#define __ARCH_WANT_SYNC_FILE_RANGE2 -#endif - -/* Use the standard ABI for syscalls. */ -#include <asm-generic/unistd.h> - -/* Additional Tilera-specific syscalls. */ -#define __NR_cacheflush (__NR_arch_specific_syscall + 1) -__SYSCALL(__NR_cacheflush, sys_cacheflush) - -#ifndef __tilegx__ -/* "Fast" syscalls provide atomic support for 32-bit chips. */ -#define __NR_FAST_cmpxchg -1 -#define __NR_FAST_atomic_update -2 -#define __NR_FAST_cmpxchg64 -3 -#define __NR_cmpxchg_badaddr (__NR_arch_specific_syscall + 0) -__SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr) -#endif - -#ifdef __KERNEL__ /* In compat mode, we use sys_llseek() for compat_sys_llseek(). */ #ifdef CONFIG_COMPAT #define __ARCH_WANT_SYS_LLSEEK #endif #define __ARCH_WANT_SYS_NEWFSTATAT -#endif +#include <uapi/asm/unistd.h> diff --git a/arch/tile/include/uapi/arch/Kbuild b/arch/tile/include/uapi/arch/Kbuild index aafaa5aa54d4..4ebc34f4768d 100644 --- a/arch/tile/include/uapi/arch/Kbuild +++ b/arch/tile/include/uapi/arch/Kbuild @@ -1 +1,18 @@ # UAPI Header export list +header-y += abi.h +header-y += chip.h +header-y += chip_tile64.h +header-y += chip_tilegx.h +header-y += chip_tilepro.h +header-y += icache.h +header-y += interrupts.h +header-y += interrupts_32.h +header-y += interrupts_64.h +header-y += opcode.h +header-y += opcode_tilegx.h +header-y += opcode_tilepro.h +header-y += sim.h +header-y += sim_def.h +header-y += spr_def.h +header-y += spr_def_32.h +header-y += spr_def_64.h diff --git a/arch/tile/include/arch/abi.h b/arch/tile/include/uapi/arch/abi.h index c55a3d432644..c55a3d432644 100644 --- a/arch/tile/include/arch/abi.h +++ b/arch/tile/include/uapi/arch/abi.h diff --git a/arch/tile/include/arch/chip.h b/arch/tile/include/uapi/arch/chip.h index 926d3db0e91e..926d3db0e91e 100644 --- a/arch/tile/include/arch/chip.h +++ b/arch/tile/include/uapi/arch/chip.h diff --git a/arch/tile/include/arch/chip_tile64.h b/arch/tile/include/uapi/arch/chip_tile64.h index 261aaba092d4..261aaba092d4 100644 --- a/arch/tile/include/arch/chip_tile64.h +++ b/arch/tile/include/uapi/arch/chip_tile64.h diff --git a/arch/tile/include/arch/chip_tilegx.h b/arch/tile/include/uapi/arch/chip_tilegx.h index ea8e4f2c9483..ea8e4f2c9483 100644 --- a/arch/tile/include/arch/chip_tilegx.h +++ b/arch/tile/include/uapi/arch/chip_tilegx.h diff --git a/arch/tile/include/arch/chip_tilepro.h b/arch/tile/include/uapi/arch/chip_tilepro.h index 70017699a74c..70017699a74c 100644 --- a/arch/tile/include/arch/chip_tilepro.h +++ b/arch/tile/include/uapi/arch/chip_tilepro.h diff --git a/arch/tile/include/arch/icache.h b/arch/tile/include/uapi/arch/icache.h index 762eafa8a11e..762eafa8a11e 100644 --- a/arch/tile/include/arch/icache.h +++ b/arch/tile/include/uapi/arch/icache.h diff --git a/arch/tile/include/arch/interrupts.h b/arch/tile/include/uapi/arch/interrupts.h index 20f8f07d2de9..20f8f07d2de9 100644 --- a/arch/tile/include/arch/interrupts.h +++ b/arch/tile/include/uapi/arch/interrupts.h diff --git a/arch/tile/include/arch/interrupts_32.h b/arch/tile/include/uapi/arch/interrupts_32.h index 96b5710505b6..96b5710505b6 100644 --- a/arch/tile/include/arch/interrupts_32.h +++ b/arch/tile/include/uapi/arch/interrupts_32.h diff --git a/arch/tile/include/arch/interrupts_64.h b/arch/tile/include/uapi/arch/interrupts_64.h index 5bb58b2e4e6f..5bb58b2e4e6f 100644 --- a/arch/tile/include/arch/interrupts_64.h +++ b/arch/tile/include/uapi/arch/interrupts_64.h diff --git a/arch/tile/include/arch/opcode.h b/arch/tile/include/uapi/arch/opcode.h index 92d15229ecec..92d15229ecec 100644 --- a/arch/tile/include/arch/opcode.h +++ b/arch/tile/include/uapi/arch/opcode.h diff --git a/arch/tile/include/arch/opcode_tilegx.h b/arch/tile/include/uapi/arch/opcode_tilegx.h index c14d02c81600..c14d02c81600 100644 --- a/arch/tile/include/arch/opcode_tilegx.h +++ b/arch/tile/include/uapi/arch/opcode_tilegx.h diff --git a/arch/tile/include/arch/opcode_tilepro.h b/arch/tile/include/uapi/arch/opcode_tilepro.h index 71b763b8ce83..71b763b8ce83 100644 --- a/arch/tile/include/arch/opcode_tilepro.h +++ b/arch/tile/include/uapi/arch/opcode_tilepro.h diff --git a/arch/tile/include/arch/sim.h b/arch/tile/include/uapi/arch/sim.h index e54b7b0527f3..e54b7b0527f3 100644 --- a/arch/tile/include/arch/sim.h +++ b/arch/tile/include/uapi/arch/sim.h diff --git a/arch/tile/include/arch/sim_def.h b/arch/tile/include/uapi/arch/sim_def.h index 4b44a2b6a09a..4b44a2b6a09a 100644 --- a/arch/tile/include/arch/sim_def.h +++ b/arch/tile/include/uapi/arch/sim_def.h diff --git a/arch/tile/include/uapi/arch/spr_def.h b/arch/tile/include/uapi/arch/spr_def.h new file mode 100644 index 000000000000..c250c5adb1a6 --- /dev/null +++ b/arch/tile/include/uapi/arch/spr_def.h @@ -0,0 +1,26 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _UAPI__ARCH_SPR_DEF_H__ +#define _UAPI__ARCH_SPR_DEF_H__ + +/* Include the proper base SPR definition file. */ +#ifdef __tilegx__ +#include <arch/spr_def_64.h> +#else +#include <arch/spr_def_32.h> +#endif + + +#endif /* _UAPI__ARCH_SPR_DEF_H__ */ diff --git a/arch/tile/include/arch/spr_def_32.h b/arch/tile/include/uapi/arch/spr_def_32.h index 78bbce2fb19a..c689446e6284 100644 --- a/arch/tile/include/arch/spr_def_32.h +++ b/arch/tile/include/uapi/arch/spr_def_32.h @@ -14,8 +14,8 @@ #ifndef __DOXYGEN__ -#ifndef __ARCH_SPR_DEF_H__ -#define __ARCH_SPR_DEF_H__ +#ifndef __ARCH_SPR_DEF_32_H__ +#define __ARCH_SPR_DEF_32_H__ #define SPR_AUX_PERF_COUNT_0 0x6005 #define SPR_AUX_PERF_COUNT_1 0x6006 @@ -252,6 +252,6 @@ #define SPR_WATCH_MASK 0x420a #define SPR_WATCH_VAL 0x420b -#endif /* !defined(__ARCH_SPR_DEF_H__) */ +#endif /* !defined(__ARCH_SPR_DEF_32_H__) */ #endif /* !defined(__DOXYGEN__) */ diff --git a/arch/tile/include/arch/spr_def_64.h b/arch/tile/include/uapi/arch/spr_def_64.h index 0da86faa3370..67a6c1751e3b 100644 --- a/arch/tile/include/arch/spr_def_64.h +++ b/arch/tile/include/uapi/arch/spr_def_64.h @@ -14,8 +14,8 @@ #ifndef __DOXYGEN__ -#ifndef __ARCH_SPR_DEF_H__ -#define __ARCH_SPR_DEF_H__ +#ifndef __ARCH_SPR_DEF_64_H__ +#define __ARCH_SPR_DEF_64_H__ #define SPR_AUX_PERF_COUNT_0 0x2105 #define SPR_AUX_PERF_COUNT_1 0x2106 @@ -211,6 +211,6 @@ #define SPR_WATCH_MASK 0x200a #define SPR_WATCH_VAL 0x200b -#endif /* !defined(__ARCH_SPR_DEF_H__) */ +#endif /* !defined(__ARCH_SPR_DEF_64_H__) */ #endif /* !defined(__DOXYGEN__) */ diff --git a/arch/tile/include/uapi/asm/Kbuild b/arch/tile/include/uapi/asm/Kbuild index baebb3da1d44..5c6915fd30b5 100644 --- a/arch/tile/include/uapi/asm/Kbuild +++ b/arch/tile/include/uapi/asm/Kbuild @@ -1,3 +1,18 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +header-y += auxvec.h +header-y += bitsperlong.h +header-y += byteorder.h +header-y += cachectl.h +header-y += hardwall.h +header-y += kvm_para.h +header-y += mman.h +header-y += ptrace.h +header-y += setup.h +header-y += sigcontext.h +header-y += siginfo.h +header-y += signal.h +header-y += stat.h +header-y += swab.h +header-y += unistd.h diff --git a/arch/tile/include/asm/auxvec.h b/arch/tile/include/uapi/asm/auxvec.h index 1d393edb0641..1d393edb0641 100644 --- a/arch/tile/include/asm/auxvec.h +++ b/arch/tile/include/uapi/asm/auxvec.h diff --git a/arch/tile/include/asm/bitsperlong.h b/arch/tile/include/uapi/asm/bitsperlong.h index 58c771f2af2f..58c771f2af2f 100644 --- a/arch/tile/include/asm/bitsperlong.h +++ b/arch/tile/include/uapi/asm/bitsperlong.h diff --git a/arch/tile/include/asm/byteorder.h b/arch/tile/include/uapi/asm/byteorder.h index fb72ecf49218..fb72ecf49218 100644 --- a/arch/tile/include/asm/byteorder.h +++ b/arch/tile/include/uapi/asm/byteorder.h diff --git a/arch/tile/include/asm/cachectl.h b/arch/tile/include/uapi/asm/cachectl.h index af4c9f9154d1..af4c9f9154d1 100644 --- a/arch/tile/include/asm/cachectl.h +++ b/arch/tile/include/uapi/asm/cachectl.h diff --git a/arch/tile/include/uapi/asm/hardwall.h b/arch/tile/include/uapi/asm/hardwall.h new file mode 100644 index 000000000000..c2169d4f4010 --- /dev/null +++ b/arch/tile/include/uapi/asm/hardwall.h @@ -0,0 +1,51 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * Provide methods for access control of per-cpu resources like + * UDN, IDN, or IPI. + */ + +#ifndef _UAPI_ASM_TILE_HARDWALL_H +#define _UAPI_ASM_TILE_HARDWALL_H + +#include <arch/chip.h> +#include <linux/ioctl.h> + +#define HARDWALL_IOCTL_BASE 0xa2 + +/* + * The HARDWALL_CREATE() ioctl is a macro with a "size" argument. + * The resulting ioctl value is passed to the kernel in conjunction + * with a pointer to a standard kernel bitmask of cpus. + * For network resources (UDN or IDN) the bitmask must physically + * represent a rectangular configuration on the chip. + * The "size" is the number of bytes of cpu mask data. + */ +#define _HARDWALL_CREATE 1 +#define HARDWALL_CREATE(size) \ + _IOC(_IOC_READ, HARDWALL_IOCTL_BASE, _HARDWALL_CREATE, (size)) + +#define _HARDWALL_ACTIVATE 2 +#define HARDWALL_ACTIVATE \ + _IO(HARDWALL_IOCTL_BASE, _HARDWALL_ACTIVATE) + +#define _HARDWALL_DEACTIVATE 3 +#define HARDWALL_DEACTIVATE \ + _IO(HARDWALL_IOCTL_BASE, _HARDWALL_DEACTIVATE) + +#define _HARDWALL_GET_ID 4 +#define HARDWALL_GET_ID \ + _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID) + + +#endif /* _UAPI_ASM_TILE_HARDWALL_H */ diff --git a/arch/tile/include/asm/kvm_para.h b/arch/tile/include/uapi/asm/kvm_para.h index 14fab8f0b957..14fab8f0b957 100644 --- a/arch/tile/include/asm/kvm_para.h +++ b/arch/tile/include/uapi/asm/kvm_para.h diff --git a/arch/tile/include/asm/mman.h b/arch/tile/include/uapi/asm/mman.h index 81b8fc348d63..81b8fc348d63 100644 --- a/arch/tile/include/asm/mman.h +++ b/arch/tile/include/uapi/asm/mman.h diff --git a/arch/tile/include/uapi/asm/ptrace.h b/arch/tile/include/uapi/asm/ptrace.h new file mode 100644 index 000000000000..c717d0fec72e --- /dev/null +++ b/arch/tile/include/uapi/asm/ptrace.h @@ -0,0 +1,88 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _UAPI_ASM_TILE_PTRACE_H +#define _UAPI_ASM_TILE_PTRACE_H + +#include <arch/chip.h> +#include <arch/abi.h> + +/* These must match struct pt_regs, below. */ +#if CHIP_WORD_SIZE() == 32 +#define PTREGS_OFFSET_REG(n) ((n)*4) +#else +#define PTREGS_OFFSET_REG(n) ((n)*8) +#endif +#define PTREGS_OFFSET_BASE 0 +#define PTREGS_OFFSET_TP PTREGS_OFFSET_REG(53) +#define PTREGS_OFFSET_SP PTREGS_OFFSET_REG(54) +#define PTREGS_OFFSET_LR PTREGS_OFFSET_REG(55) +#define PTREGS_NR_GPRS 56 +#define PTREGS_OFFSET_PC PTREGS_OFFSET_REG(56) +#define PTREGS_OFFSET_EX1 PTREGS_OFFSET_REG(57) +#define PTREGS_OFFSET_FAULTNUM PTREGS_OFFSET_REG(58) +#define PTREGS_OFFSET_ORIG_R0 PTREGS_OFFSET_REG(59) +#define PTREGS_OFFSET_FLAGS PTREGS_OFFSET_REG(60) +#if CHIP_HAS_CMPEXCH() +#define PTREGS_OFFSET_CMPEXCH PTREGS_OFFSET_REG(61) +#endif +#define PTREGS_SIZE PTREGS_OFFSET_REG(64) + + +#ifndef __ASSEMBLY__ + +#ifndef __KERNEL__ +/* Provide appropriate length type to userspace regardless of -m32/-m64. */ +typedef uint_reg_t pt_reg_t; +#endif + +/* + * This struct defines the way the registers are stored on the stack during a + * system call or exception. "struct sigcontext" has the same shape. + */ +struct pt_regs { + /* Saved main processor registers; 56..63 are special. */ + /* tp, sp, and lr must immediately follow regs[] for aliasing. */ + pt_reg_t regs[53]; + pt_reg_t tp; /* aliases regs[TREG_TP] */ + pt_reg_t sp; /* aliases regs[TREG_SP] */ + pt_reg_t lr; /* aliases regs[TREG_LR] */ + + /* Saved special registers. */ + pt_reg_t pc; /* stored in EX_CONTEXT_K_0 */ + pt_reg_t ex1; /* stored in EX_CONTEXT_K_1 (PL and ICS bit) */ + pt_reg_t faultnum; /* fault number (INT_SWINT_1 for syscall) */ + pt_reg_t orig_r0; /* r0 at syscall entry, else zero */ + pt_reg_t flags; /* flags (see below) */ +#if !CHIP_HAS_CMPEXCH() + pt_reg_t pad[3]; +#else + pt_reg_t cmpexch; /* value of CMPEXCH_VALUE SPR at interrupt */ + pt_reg_t pad[2]; +#endif +}; + +#endif /* __ASSEMBLY__ */ + +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 + +/* Support TILE-specific ptrace options, with events starting at 16. */ +#define PTRACE_O_TRACEMIGRATE 0x00010000 +#define PTRACE_EVENT_MIGRATE 16 + + +#endif /* _UAPI_ASM_TILE_PTRACE_H */ diff --git a/arch/tile/include/uapi/asm/setup.h b/arch/tile/include/uapi/asm/setup.h new file mode 100644 index 000000000000..e6f7da265ac3 --- /dev/null +++ b/arch/tile/include/uapi/asm/setup.h @@ -0,0 +1,21 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _UAPI_ASM_TILE_SETUP_H +#define _UAPI_ASM_TILE_SETUP_H + +#define COMMAND_LINE_SIZE 2048 + + +#endif /* _UAPI_ASM_TILE_SETUP_H */ diff --git a/arch/tile/include/asm/sigcontext.h b/arch/tile/include/uapi/asm/sigcontext.h index 6348e59d3724..6348e59d3724 100644 --- a/arch/tile/include/asm/sigcontext.h +++ b/arch/tile/include/uapi/asm/sigcontext.h diff --git a/arch/tile/include/asm/siginfo.h b/arch/tile/include/uapi/asm/siginfo.h index 56d661bb010b..56d661bb010b 100644 --- a/arch/tile/include/asm/siginfo.h +++ b/arch/tile/include/uapi/asm/siginfo.h diff --git a/arch/tile/include/uapi/asm/signal.h b/arch/tile/include/uapi/asm/signal.h new file mode 100644 index 000000000000..ef0d32d84a4c --- /dev/null +++ b/arch/tile/include/uapi/asm/signal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _UAPI_ASM_TILE_SIGNAL_H +#define _UAPI_ASM_TILE_SIGNAL_H + +/* Do not notify a ptracer when this signal is handled. */ +#define SA_NOPTRACE 0x02000000u + +/* Used in earlier Tilera releases, so keeping for binary compatibility. */ +#define SA_RESTORER 0x04000000u + +#include <asm-generic/signal.h> + + +#endif /* _UAPI_ASM_TILE_SIGNAL_H */ diff --git a/arch/tile/include/asm/stat.h b/arch/tile/include/uapi/asm/stat.h index c0db34d56be3..c0db34d56be3 100644 --- a/arch/tile/include/asm/stat.h +++ b/arch/tile/include/uapi/asm/stat.h diff --git a/arch/tile/include/asm/swab.h b/arch/tile/include/uapi/asm/swab.h index 7c37b38f6c8d..7c37b38f6c8d 100644 --- a/arch/tile/include/asm/swab.h +++ b/arch/tile/include/uapi/asm/swab.h diff --git a/arch/tile/include/uapi/asm/unistd.h b/arch/tile/include/uapi/asm/unistd.h new file mode 100644 index 000000000000..cd7b6dd9d471 --- /dev/null +++ b/arch/tile/include/uapi/asm/unistd.h @@ -0,0 +1,34 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#if !defined(__LP64__) || defined(__SYSCALL_COMPAT) +/* Use the flavor of this syscall that matches the 32-bit API better. */ +#define __ARCH_WANT_SYNC_FILE_RANGE2 +#endif + +/* Use the standard ABI for syscalls. */ +#include <asm-generic/unistd.h> + +/* Additional Tilera-specific syscalls. */ +#define __NR_cacheflush (__NR_arch_specific_syscall + 1) +__SYSCALL(__NR_cacheflush, sys_cacheflush) + +#ifndef __tilegx__ +/* "Fast" syscalls provide atomic support for 32-bit chips. */ +#define __NR_FAST_cmpxchg -1 +#define __NR_FAST_atomic_update -2 +#define __NR_FAST_cmpxchg64 -3 +#define __NR_cmpxchg_badaddr (__NR_arch_specific_syscall + 0) +__SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr) +#endif diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 7bc0859a9f5e..08b4fe1717bb 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -354,15 +354,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->regs[1] = ptr_to_compat_reg(&frame->info); regs->regs[2] = ptr_to_compat_reg(&frame->uc); regs->flags |= PT_FLAGS_CALLER_SAVES; - - /* - * Notify any tracer that was single-stepping it. - * The tracer may want to single-step inside the - * handler too. - */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - return 0; give_sigsegv: diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 6be799150501..307d010696c9 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -548,6 +548,9 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) if (!user_mode(regs)) return 0; + /* Enable interrupts; they are disabled again on return to caller. */ + local_irq_enable(); + if (thread_info_flags & _TIF_NEED_RESCHED) { schedule(); return 1; @@ -594,13 +597,13 @@ SYSCALL_DEFINE4(execve, const char __user *, path, struct pt_regs *, regs) { long error; - char *filename; + struct filename *filename; filename = getname(path); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); if (error == 0) single_step_execve(); @@ -615,13 +618,13 @@ long compat_sys_execve(const char __user *path, struct pt_regs *regs) { long error; - char *filename; + struct filename *filename; filename = getname(path); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = compat_do_execve(filename, argv, envp, regs); + error = compat_do_execve(filename->name, argv, envp, regs); putname(filename); if (error == 0) single_step_execve(); diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index e29b0553211d..67efb656d104 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c @@ -219,15 +219,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->regs[1] = (unsigned long) &frame->info; regs->regs[2] = (unsigned long) &frame->uc; regs->flags |= PT_FLAGS_CALLER_SAVES; - - /* - * Notify any tracer that was single-stepping it. - * The tracer may want to single-step inside the - * handler too. - */ - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - return 0; give_sigsegv: @@ -278,7 +269,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info, ret = setup_rt_frame(sig, ka, info, oldset, regs); if (ret) return; - signal_delivered(sig, info, ka, regs, 0); + signal_delivered(sig, info, ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } /* diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index 1e82e954e978..c03cd5a02364 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -26,7 +26,6 @@ struct thread_struct { jmp_buf *fault_catcher; struct task_struct *prev_sched; unsigned long temp_stack; - jmp_buf *exec_buf; struct arch_thread arch; jmp_buf switch_buf; int mm_count; @@ -54,7 +53,6 @@ struct thread_struct { .fault_addr = NULL, \ .prev_sched = NULL, \ .temp_stack = 0, \ - .exec_buf = NULL, \ .arch = INIT_ARCH_THREAD, \ .request = { 0 } \ } diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h index c04e5ab68f56..2c8eeb2df8b4 100644 --- a/arch/um/include/asm/thread_info.h +++ b/arch/um/include/asm/thread_info.h @@ -65,8 +65,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling - * TIF_NEED_RESCHED */ #define TIF_RESTART_BLOCK 4 #define TIF_MEMDIE 5 /* is terminating due to OOM killer */ #define TIF_SYSCALL_AUDIT 6 @@ -76,7 +74,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_MEMDIE (1 << TIF_MEMDIE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 44883049c11d..95feaa47a2fb 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -191,7 +191,6 @@ extern int os_getpid(void); extern int os_getpgrp(void); extern void init_new_thread_signals(void); -extern int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr); extern int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x); diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index ab019c7f0b57..3a8ece7d09ca 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -47,8 +47,3 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) #endif } EXPORT_SYMBOL(start_thread); - -void __noreturn ret_from_kernel_execve(struct pt_regs *unused) -{ - UML_LONGJMP(current->thread.exec_buf, 1); -} diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 30629783b3e0..b6d699cdd557 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -135,14 +135,10 @@ void new_thread_handler(void) arg = current->thread.request.u.thread.arg; /* - * The return value is 1 if the kernel thread execs a process, - * 0 if it just exits + * callback returns only if the kernel thread execs a process */ - n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); - if (n == 1) - userspace(¤t->thread.regs.regs); - else - do_exit(0); + n = fn(arg); + userspace(¤t->thread.regs.regs); } /* Called magically, see new_thread_handler above */ diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 162bea3d91b2..b8f34c9e53ae 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -244,16 +244,3 @@ void init_new_thread_signals(void) signal(SIGWINCH, SIG_IGN); signal(SIGTERM, SIG_DFL); } - -int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) -{ - jmp_buf buf; - int n; - - *jmp_ptr = &buf; - n = UML_SETJMP(&buf); - if (n != 0) - return n; - (*fn)(arg); - return 0; -} diff --git a/arch/unicore32/include/asm/thread_info.h b/arch/unicore32/include/asm/thread_info.h index 89f7557583b8..818b4a1edb5b 100644 --- a/arch/unicore32/include/asm/thread_info.h +++ b/arch/unicore32/include/asm/thread_info.h @@ -141,12 +141,12 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) -#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) /* * Change these and you break ASM code in entry-common.S */ -#define _TIF_WORK_MASK 0x000000ff +#define _TIF_WORK_MASK \ + (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME) #endif /* __KERNEL__ */ #endif /* __UNICORE_THREAD_INFO_H__ */ diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S index 00a259f9819e..dcb87ab19ddd 100644 --- a/arch/unicore32/kernel/entry.S +++ b/arch/unicore32/kernel/entry.S @@ -544,8 +544,6 @@ fast_work_pending: work_pending: cand.a r1, #_TIF_NEED_RESCHED bne work_resched - cand.a r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME - beq no_work_pending mov r0, sp @ 'regs' mov r2, why @ 'syscall' cand.a r1, #_TIF_SIGPENDING @ delivering a signal? diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c index 8adedb37720a..b8b2ffd774d6 100644 --- a/arch/unicore32/kernel/signal.c +++ b/arch/unicore32/kernel/signal.c @@ -12,7 +12,6 @@ #include <linux/errno.h> #include <linux/signal.h> #include <linux/personality.h> -#include <linux/freezer.h> #include <linux/uaccess.h> #include <linux/tracehook.h> #include <linux/elf.h> diff --git a/arch/unicore32/kernel/sys.c b/arch/unicore32/kernel/sys.c index 5fd9af773e15..fabdee96110b 100644 --- a/arch/unicore32/kernel/sys.c +++ b/arch/unicore32/kernel/sys.c @@ -51,13 +51,13 @@ asmlinkage long __sys_execve(const char __user *filename, struct pt_regs *regs) { int error; - char *fn; + struct filename *fn; fn = getname(filename); error = PTR_ERR(fn); if (IS_ERR(fn)) goto out; - error = do_execve(fn, argv, envp, regs); + error = do_execve(fn->name, argv, envp, regs); putname(fn); out: return error; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 42d2c35a5bbd..70071b19eb98 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -109,6 +109,7 @@ config X86 select HAVE_RCU_USER_QS if X86_64 select HAVE_IRQ_TIME_ACCOUNTING select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE config INSTRUCTION_DECODER def_bool y diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index fbee9714d9ab..7f0edceb7563 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -121,6 +121,11 @@ #define MSR_P6_EVNTSEL0 0x00000186 #define MSR_P6_EVNTSEL1 0x00000187 +#define MSR_KNC_PERFCTR0 0x00000020 +#define MSR_KNC_PERFCTR1 0x00000021 +#define MSR_KNC_EVNTSEL0 0x00000028 +#define MSR_KNC_EVNTSEL1 0x00000029 + /* AMD64 MSRs. Not complete. See the architecture manual for a more complete list. */ diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 55d155560fdf..16f3fc6ebf2e 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -51,7 +51,6 @@ # define __ARCH_WANT_SYS_UTIME # define __ARCH_WANT_SYS_WAITPID # define __ARCH_WANT_SYS_EXECVE -# define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index 8b38be2de9e1..46e24d36b7da 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h @@ -17,8 +17,8 @@ struct vsyscall_gtod_data { /* open coded 'struct timespec' */ time_t wall_time_sec; - u32 wall_time_nsec; - u32 monotonic_time_nsec; + u64 wall_time_snsec; + u64 monotonic_time_snsec; time_t monotonic_time_sec; struct timezone sys_tz; diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index d30a6a9a0121..a0e067d3d96c 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -32,7 +32,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o ifdef CONFIG_PERF_EVENTS obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o -obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o endif diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 8b6defe7eefc..271d25700297 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -626,6 +626,8 @@ int p4_pmu_init(void); int p6_pmu_init(void); +int knc_pmu_init(void); + #else /* CONFIG_CPU_SUP_INTEL */ static inline void reserve_ds_buffers(void) diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c index eebd5ffe1bba..6336bcbd0618 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c +++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c @@ -41,17 +41,22 @@ struct cpu_perf_ibs { }; struct perf_ibs { - struct pmu pmu; - unsigned int msr; - u64 config_mask; - u64 cnt_mask; - u64 enable_mask; - u64 valid_mask; - u64 max_period; - unsigned long offset_mask[1]; - int offset_max; - struct cpu_perf_ibs __percpu *pcpu; - u64 (*get_count)(u64 config); + struct pmu pmu; + unsigned int msr; + u64 config_mask; + u64 cnt_mask; + u64 enable_mask; + u64 valid_mask; + u64 max_period; + unsigned long offset_mask[1]; + int offset_max; + struct cpu_perf_ibs __percpu *pcpu; + + struct attribute **format_attrs; + struct attribute_group format_group; + const struct attribute_group *attr_groups[2]; + + u64 (*get_count)(u64 config); }; struct perf_ibs_data { @@ -446,6 +451,19 @@ static void perf_ibs_del(struct perf_event *event, int flags) static void perf_ibs_read(struct perf_event *event) { } +PMU_FORMAT_ATTR(rand_en, "config:57"); +PMU_FORMAT_ATTR(cnt_ctl, "config:19"); + +static struct attribute *ibs_fetch_format_attrs[] = { + &format_attr_rand_en.attr, + NULL, +}; + +static struct attribute *ibs_op_format_attrs[] = { + NULL, /* &format_attr_cnt_ctl.attr if IBS_CAPS_OPCNT */ + NULL, +}; + static struct perf_ibs perf_ibs_fetch = { .pmu = { .task_ctx_nr = perf_invalid_context, @@ -465,6 +483,7 @@ static struct perf_ibs perf_ibs_fetch = { .max_period = IBS_FETCH_MAX_CNT << 4, .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, + .format_attrs = ibs_fetch_format_attrs, .get_count = get_ibs_fetch_count, }; @@ -488,6 +507,7 @@ static struct perf_ibs perf_ibs_op = { .max_period = IBS_OP_MAX_CNT << 4, .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, .offset_max = MSR_AMD64_IBSOP_REG_COUNT, + .format_attrs = ibs_op_format_attrs, .get_count = get_ibs_op_count, }; @@ -597,6 +617,17 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) perf_ibs->pcpu = pcpu; + /* register attributes */ + if (perf_ibs->format_attrs[0]) { + memset(&perf_ibs->format_group, 0, sizeof(perf_ibs->format_group)); + perf_ibs->format_group.name = "format"; + perf_ibs->format_group.attrs = perf_ibs->format_attrs; + + memset(&perf_ibs->attr_groups, 0, sizeof(perf_ibs->attr_groups)); + perf_ibs->attr_groups[0] = &perf_ibs->format_group; + perf_ibs->pmu.attr_groups = perf_ibs->attr_groups; + } + ret = perf_pmu_register(&perf_ibs->pmu, name, -1); if (ret) { perf_ibs->pcpu = NULL; @@ -608,13 +639,19 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) static __init int perf_event_ibs_init(void) { + struct attribute **attr = ibs_op_format_attrs; + if (!ibs_caps) return -ENODEV; /* ibs not supported by the cpu */ perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); - if (ibs_caps & IBS_CAPS_OPCNT) + + if (ibs_caps & IBS_CAPS_OPCNT) { perf_ibs_op.config_mask |= IBS_OP_CNT_CTL; + *attr++ = &format_attr_cnt_ctl.attr; + } perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); + register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs"); printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps); diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 6bca492b8547..324bb523d9d9 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1906,6 +1906,8 @@ __init int intel_pmu_init(void) switch (boot_cpu_data.x86) { case 0x6: return p6_pmu_init(); + case 0xb: + return knc_pmu_init(); case 0xf: return p4_pmu_init(); } diff --git a/arch/x86/kernel/cpu/perf_event_knc.c b/arch/x86/kernel/cpu/perf_event_knc.c new file mode 100644 index 000000000000..7c46bfdbc373 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_knc.c @@ -0,0 +1,248 @@ +/* Driver for Intel Xeon Phi "Knights Corner" PMU */ + +#include <linux/perf_event.h> +#include <linux/types.h> + +#include "perf_event.h" + +static const u64 knc_perfmon_event_map[] = +{ + [PERF_COUNT_HW_CPU_CYCLES] = 0x002a, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x0016, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0028, + [PERF_COUNT_HW_CACHE_MISSES] = 0x0029, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0012, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x002b, +}; + +static __initconst u64 knc_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + /* On Xeon Phi event "0" is a valid DATA_READ */ + /* (L1 Data Cache Reads) Instruction. */ + /* We code this as ARCH_PERFMON_EVENTSEL_INT as this */ + /* bit will always be set in x86_pmu_hw_config(). */ + [ C(RESULT_ACCESS) ] = ARCH_PERFMON_EVENTSEL_INT, + /* DATA_READ */ + [ C(RESULT_MISS) ] = 0x0003, /* DATA_READ_MISS */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0001, /* DATA_WRITE */ + [ C(RESULT_MISS) ] = 0x0004, /* DATA_WRITE_MISS */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0011, /* L1_DATA_PF1 */ + [ C(RESULT_MISS) ] = 0x001c, /* L1_DATA_PF1_MISS */ + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x000c, /* CODE_READ */ + [ C(RESULT_MISS) ] = 0x000e, /* CODE_CACHE_MISS */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(LL ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0x10cb, /* L2_READ_MISS */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x10cc, /* L2_WRITE_HIT */ + [ C(RESULT_MISS) ] = 0, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x10fc, /* L2_DATA_PF2 */ + [ C(RESULT_MISS) ] = 0x10fe, /* L2_DATA_PF2_MISS */ + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = ARCH_PERFMON_EVENTSEL_INT, + /* DATA_READ */ + /* see note on L1 OP_READ */ + [ C(RESULT_MISS) ] = 0x0002, /* DATA_PAGE_WALK */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0001, /* DATA_WRITE */ + [ C(RESULT_MISS) ] = 0x0002, /* DATA_PAGE_WALK */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x000c, /* CODE_READ */ + [ C(RESULT_MISS) ] = 0x000d, /* CODE_PAGE_WALK */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0012, /* BRANCHES */ + [ C(RESULT_MISS) ] = 0x002b, /* BRANCHES_MISPREDICTED */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + + +static u64 knc_pmu_event_map(int hw_event) +{ + return knc_perfmon_event_map[hw_event]; +} + +static struct event_constraint knc_event_constraints[] = +{ + INTEL_EVENT_CONSTRAINT(0xc3, 0x1), /* HWP_L2HIT */ + INTEL_EVENT_CONSTRAINT(0xc4, 0x1), /* HWP_L2MISS */ + INTEL_EVENT_CONSTRAINT(0xc8, 0x1), /* L2_READ_HIT_E */ + INTEL_EVENT_CONSTRAINT(0xc9, 0x1), /* L2_READ_HIT_M */ + INTEL_EVENT_CONSTRAINT(0xca, 0x1), /* L2_READ_HIT_S */ + INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* L2_READ_MISS */ + INTEL_EVENT_CONSTRAINT(0xcc, 0x1), /* L2_WRITE_HIT */ + INTEL_EVENT_CONSTRAINT(0xce, 0x1), /* L2_STRONGLY_ORDERED_STREAMING_VSTORES_MISS */ + INTEL_EVENT_CONSTRAINT(0xcf, 0x1), /* L2_WEAKLY_ORDERED_STREAMING_VSTORE_MISS */ + INTEL_EVENT_CONSTRAINT(0xd7, 0x1), /* L2_VICTIM_REQ_WITH_DATA */ + INTEL_EVENT_CONSTRAINT(0xe3, 0x1), /* SNP_HITM_BUNIT */ + INTEL_EVENT_CONSTRAINT(0xe6, 0x1), /* SNP_HIT_L2 */ + INTEL_EVENT_CONSTRAINT(0xe7, 0x1), /* SNP_HITM_L2 */ + INTEL_EVENT_CONSTRAINT(0xf1, 0x1), /* L2_DATA_READ_MISS_CACHE_FILL */ + INTEL_EVENT_CONSTRAINT(0xf2, 0x1), /* L2_DATA_WRITE_MISS_CACHE_FILL */ + INTEL_EVENT_CONSTRAINT(0xf6, 0x1), /* L2_DATA_READ_MISS_MEM_FILL */ + INTEL_EVENT_CONSTRAINT(0xf7, 0x1), /* L2_DATA_WRITE_MISS_MEM_FILL */ + INTEL_EVENT_CONSTRAINT(0xfc, 0x1), /* L2_DATA_PF2 */ + INTEL_EVENT_CONSTRAINT(0xfd, 0x1), /* L2_DATA_PF2_DROP */ + INTEL_EVENT_CONSTRAINT(0xfe, 0x1), /* L2_DATA_PF2_MISS */ + INTEL_EVENT_CONSTRAINT(0xff, 0x1), /* L2_DATA_HIT_INFLIGHT_PF2 */ + EVENT_CONSTRAINT_END +}; + +#define MSR_KNC_IA32_PERF_GLOBAL_STATUS 0x0000002d +#define MSR_KNC_IA32_PERF_GLOBAL_OVF_CONTROL 0x0000002e +#define MSR_KNC_IA32_PERF_GLOBAL_CTRL 0x0000002f + +#define KNC_ENABLE_COUNTER0 0x00000001 +#define KNC_ENABLE_COUNTER1 0x00000002 + +static void knc_pmu_disable_all(void) +{ + u64 val; + + rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); + val &= ~(KNC_ENABLE_COUNTER0|KNC_ENABLE_COUNTER1); + wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); +} + +static void knc_pmu_enable_all(int added) +{ + u64 val; + + rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); + val |= (KNC_ENABLE_COUNTER0|KNC_ENABLE_COUNTER1); + wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); +} + +static inline void +knc_pmu_disable_event(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + u64 val; + + val = hwc->config; + if (cpuc->enabled) + val &= ~ARCH_PERFMON_EVENTSEL_ENABLE; + + (void)wrmsrl_safe(hwc->config_base + hwc->idx, val); +} + +static void knc_pmu_enable_event(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + u64 val; + + val = hwc->config; + if (cpuc->enabled) + val |= ARCH_PERFMON_EVENTSEL_ENABLE; + + (void)wrmsrl_safe(hwc->config_base + hwc->idx, val); +} + +PMU_FORMAT_ATTR(event, "config:0-7" ); +PMU_FORMAT_ATTR(umask, "config:8-15" ); +PMU_FORMAT_ATTR(edge, "config:18" ); +PMU_FORMAT_ATTR(inv, "config:23" ); +PMU_FORMAT_ATTR(cmask, "config:24-31" ); + +static struct attribute *intel_knc_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask.attr, + NULL, +}; + +static __initconst struct x86_pmu knc_pmu = { + .name = "knc", + .handle_irq = x86_pmu_handle_irq, + .disable_all = knc_pmu_disable_all, + .enable_all = knc_pmu_enable_all, + .enable = knc_pmu_enable_event, + .disable = knc_pmu_disable_event, + .hw_config = x86_pmu_hw_config, + .schedule_events = x86_schedule_events, + .eventsel = MSR_KNC_EVNTSEL0, + .perfctr = MSR_KNC_PERFCTR0, + .event_map = knc_pmu_event_map, + .max_events = ARRAY_SIZE(knc_perfmon_event_map), + .apic = 1, + .max_period = (1ULL << 31) - 1, + .version = 0, + .num_counters = 2, + /* in theory 40 bits, early silicon is buggy though */ + .cntval_bits = 32, + .cntval_mask = (1ULL << 32) - 1, + .get_event_constraints = x86_get_event_constraints, + .event_constraints = knc_event_constraints, + .format_attrs = intel_knc_formats_attr, +}; + +__init int knc_pmu_init(void) +{ + x86_pmu = knc_pmu; + + memcpy(hw_cache_event_ids, knc_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + return 0; +} diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c index 966512b2cacf..2e8caf03f593 100644 --- a/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/arch/x86/kernel/cpu/perfctr-watchdog.c @@ -56,6 +56,8 @@ static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) switch (boot_cpu_data.x86) { case 6: return msr - MSR_P6_PERFCTR0; + case 11: + return msr - MSR_KNC_PERFCTR0; case 15: return msr - MSR_P4_BPU_PERFCTR0; } @@ -82,6 +84,8 @@ static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) switch (boot_cpu_data.x86) { case 6: return msr - MSR_P6_EVNTSEL0; + case 11: + return msr - MSR_KNC_EVNTSEL0; case 15: return msr - MSR_P4_BSU_ESCR0; } diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 8f9ed1afde8f..a1193aef6d7d 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -299,12 +299,20 @@ ENTRY(ret_from_fork) CFI_ENDPROC END(ret_from_fork) -ENTRY(ret_from_kernel_execve) - movl %eax, %esp - movl $0,PT_EAX(%esp) +ENTRY(ret_from_kernel_thread) + CFI_STARTPROC + pushl_cfi %eax + call schedule_tail GET_THREAD_INFO(%ebp) + popl_cfi %eax + pushl_cfi $0x0202 # Reset kernel eflags + popfl_cfi + movl PT_EBP(%esp),%eax + call *PT_EBX(%esp) + movl $0,PT_EAX(%esp) jmp syscall_exit -END(ret_from_kernel_execve) + CFI_ENDPROC +ENDPROC(ret_from_kernel_thread) /* * Interrupt exit functions should be protected against kprobes @@ -622,6 +630,10 @@ work_notifysig: # deal with pending signals and movl %esp, %eax jne work_notifysig_v86 # returning to kernel-space or # vm86-space +1: +#else + movl %esp, %eax +#endif TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) movb PT_CS(%esp), %bl @@ -632,24 +644,15 @@ work_notifysig: # deal with pending signals and call do_notify_resume jmp resume_userspace +#ifdef CONFIG_VM86 ALIGN work_notifysig_v86: pushl_cfi %ecx # save ti_flags for do_notify_resume call save_v86_state # %eax contains pt_regs pointer popl_cfi %ecx movl %eax, %esp -#else - movl %esp, %eax + jmp 1b #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 END(work_pending) # perform syscall exit tracing @@ -1020,21 +1023,6 @@ END(spurious_interrupt_bug) */ .popsection -ENTRY(ret_from_kernel_thread) - CFI_STARTPROC - pushl_cfi %eax - call schedule_tail - GET_THREAD_INFO(%ebp) - popl_cfi %eax - pushl_cfi $0x0202 # Reset kernel eflags - popfl_cfi - movl PT_EBP(%esp),%eax - call *PT_EBX(%esp) - call do_exit - ud2 # padding for call trace - CFI_ENDPROC -ENDPROC(ret_from_kernel_thread) - #ifdef CONFIG_XEN /* Xen doesn't set %esp to be precisely what the normal sysenter entrypoint expects, so fix it up before using the normal path. */ diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index cdc790c78f32..0c58952d64e8 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -563,15 +563,13 @@ ENTRY(ret_from_fork) jmp ret_from_sys_call # go to the SYSRET fastpath 1: - subq $REST_SKIP, %rsp # move the stack pointer back + subq $REST_SKIP, %rsp # leave space for volatiles CFI_ADJUST_CFA_OFFSET REST_SKIP movq %rbp, %rdi call *%rbx - # exit - mov %eax, %edi - call do_exit - ud2 # padding for call trace - + movl $0, RAX(%rsp) + RESTORE_REST + jmp int_ret_from_sys_call CFI_ENDPROC END(ret_from_fork) @@ -1326,20 +1324,6 @@ bad_gs: jmp 2b .previous -ENTRY(ret_from_kernel_execve) - movq %rdi, %rsp - movl $0, RAX(%rsp) - // RESTORE_REST - movq 0*8(%rsp), %r15 - movq 1*8(%rsp), %r14 - movq 2*8(%rsp), %r13 - movq 3*8(%rsp), %r12 - movq 4*8(%rsp), %rbp - movq 5*8(%rsp), %rbx - addq $(6*8), %rsp - jmp int_ret_from_sys_call -END(ret_from_kernel_execve) - /* Call softirq on interrupt stack. Interrupts are off. */ ENTRY(call_softirq) CFI_STARTPROC diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d609be046b57..a2bb18e02839 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -68,6 +68,7 @@ #include <linux/percpu.h> #include <linux/crash_dump.h> #include <linux/tboot.h> +#include <linux/jiffies.h> #include <video/edid.h> @@ -1032,6 +1033,8 @@ void __init setup_arch(char **cmdline_p) mcheck_init(); arch_init_ideal_nops(); + + register_refined_jiffies(CLOCK_TICK_RATE); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 8d141b309046..3a3e8c9e280d 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -28,7 +28,7 @@ #include <linux/jiffies.h> #include <linux/sysctl.h> #include <linux/topology.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/getcpu.h> #include <linux/cpu.h> #include <linux/smp.h> @@ -82,32 +82,41 @@ void update_vsyscall_tz(void) vsyscall_gtod_data.sys_tz = sys_tz; } -void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, - struct clocksource *clock, u32 mult) +void update_vsyscall(struct timekeeper *tk) { - struct timespec monotonic; + struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data; - write_seqcount_begin(&vsyscall_gtod_data.seq); + write_seqcount_begin(&vdata->seq); /* copy vsyscall data */ - vsyscall_gtod_data.clock.vclock_mode = clock->archdata.vclock_mode; - vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; - vsyscall_gtod_data.clock.mask = clock->mask; - vsyscall_gtod_data.clock.mult = mult; - vsyscall_gtod_data.clock.shift = clock->shift; - - vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; - vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode; + vdata->clock.cycle_last = tk->clock->cycle_last; + vdata->clock.mask = tk->clock->mask; + vdata->clock.mult = tk->mult; + vdata->clock.shift = tk->shift; + + vdata->wall_time_sec = tk->xtime_sec; + vdata->wall_time_snsec = tk->xtime_nsec; + + vdata->monotonic_time_sec = tk->xtime_sec + + tk->wall_to_monotonic.tv_sec; + vdata->monotonic_time_snsec = tk->xtime_nsec + + (tk->wall_to_monotonic.tv_nsec + << tk->shift); + while (vdata->monotonic_time_snsec >= + (((u64)NSEC_PER_SEC) << tk->shift)) { + vdata->monotonic_time_snsec -= + ((u64)NSEC_PER_SEC) << tk->shift; + vdata->monotonic_time_sec++; + } - monotonic = timespec_add(*wall_time, *wtm); - vsyscall_gtod_data.monotonic_time_sec = monotonic.tv_sec; - vsyscall_gtod_data.monotonic_time_nsec = monotonic.tv_nsec; + vdata->wall_time_coarse.tv_sec = tk->xtime_sec; + vdata->wall_time_coarse.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); - vsyscall_gtod_data.wall_time_coarse = __current_kernel_time(); - vsyscall_gtod_data.monotonic_time_coarse = - timespec_add(vsyscall_gtod_data.wall_time_coarse, *wtm); + vdata->monotonic_time_coarse = timespec_add(vdata->wall_time_coarse, + tk->wall_to_monotonic); - write_seqcount_end(&vsyscall_gtod_data.seq); + write_seqcount_end(&vdata->seq); } static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index 30c4eec033af..9fa950df80e5 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig @@ -14,6 +14,7 @@ config UML_X86 def_bool y select GENERIC_FIND_FIRST_BIT select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE config 64BIT bool "64-bit kernel" if SUBARCH = "x86" diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 885eff49d6ab..4df6c373421a 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c @@ -80,7 +80,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) } -notrace static inline long vgetns(void) +notrace static inline u64 vgetsns(void) { long v; cycles_t cycles; @@ -91,21 +91,24 @@ notrace static inline long vgetns(void) else return 0; v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask; - return (v * gtod->clock.mult) >> gtod->clock.shift; + return v * gtod->clock.mult; } /* Code size doesn't matter (vdso is 4k anyway) and this is faster. */ notrace static int __always_inline do_realtime(struct timespec *ts) { - unsigned long seq, ns; + unsigned long seq; + u64 ns; int mode; + ts->tv_nsec = 0; do { seq = read_seqcount_begin(>od->seq); mode = gtod->clock.vclock_mode; ts->tv_sec = gtod->wall_time_sec; - ts->tv_nsec = gtod->wall_time_nsec; - ns = vgetns(); + ns = gtod->wall_time_snsec; + ns += vgetsns(); + ns >>= gtod->clock.shift; } while (unlikely(read_seqcount_retry(>od->seq, seq))); timespec_add_ns(ts, ns); @@ -114,15 +117,18 @@ notrace static int __always_inline do_realtime(struct timespec *ts) notrace static int do_monotonic(struct timespec *ts) { - unsigned long seq, ns; + unsigned long seq; + u64 ns; int mode; + ts->tv_nsec = 0; do { seq = read_seqcount_begin(>od->seq); mode = gtod->clock.vclock_mode; ts->tv_sec = gtod->monotonic_time_sec; - ts->tv_nsec = gtod->monotonic_time_nsec; - ns = vgetns(); + ns = gtod->monotonic_time_snsec; + ns += vgetsns(); + ns >>= gtod->clock.shift; } while (unlikely(read_seqcount_retry(>od->seq, seq))); timespec_add_ns(ts, ns); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bf788d34530d..e3497f240eab 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -987,7 +987,16 @@ static void xen_write_cr4(unsigned long cr4) native_write_cr4(cr4); } - +#ifdef CONFIG_X86_64 +static inline unsigned long xen_read_cr8(void) +{ + return 0; +} +static inline void xen_write_cr8(unsigned long val) +{ + BUG_ON(val); +} +#endif static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int ret; @@ -1156,6 +1165,11 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_cr4_safe = native_read_cr4_safe, .write_cr4 = xen_write_cr4, +#ifdef CONFIG_X86_64 + .read_cr8 = xen_read_cr8, + .write_cr8 = xen_write_cr8, +#endif + .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, @@ -1164,6 +1178,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, + .read_tscp = native_read_tscp, + .iret = xen_iret, .irq_enable_sysexit = xen_sysexit, #ifdef CONFIG_X86_64 diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index fd28d86fe3d2..6226c99729b9 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -47,6 +47,7 @@ #include <linux/gfp.h> #include <linux/memblock.h> #include <linux/seq_file.h> +#include <linux/crash_dump.h> #include <trace/events/xen.h> @@ -2381,6 +2382,43 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); #ifdef CONFIG_XEN_PVHVM +#ifdef CONFIG_PROC_VMCORE +/* + * This function is used in two contexts: + * - the kdump kernel has to check whether a pfn of the crashed kernel + * was a ballooned page. vmcore is using this function to decide + * whether to access a pfn of the crashed kernel. + * - the kexec kernel has to check whether a pfn was ballooned by the + * previous kernel. If the pfn is ballooned, handle it properly. + * Returns 0 if the pfn is not backed by a RAM page, the caller may + * handle the pfn special in this case. + */ +static int xen_oldmem_pfn_is_ram(unsigned long pfn) +{ + struct xen_hvm_get_mem_type a = { + .domid = DOMID_SELF, + .pfn = pfn, + }; + int ram; + + if (HYPERVISOR_hvm_op(HVMOP_get_mem_type, &a)) + return -ENXIO; + + switch (a.mem_type) { + case HVMMEM_mmio_dm: + ram = 0; + break; + case HVMMEM_ram_rw: + case HVMMEM_ram_ro: + default: + ram = 1; + break; + } + + return ram; +} +#endif + static void xen_hvm_exit_mmap(struct mm_struct *mm) { struct xen_hvm_pagetable_dying a; @@ -2411,6 +2449,9 @@ void __init xen_hvm_init_mmu_ops(void) { if (is_pagetable_dying_supported()) pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap; +#ifdef CONFIG_PROC_VMCORE + register_oldmem_pfn_is_ram(&xen_oldmem_pfn_is_ram); +#endif } #endif diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h index 81abfd5d01ac..9481004ac119 100644 --- a/arch/xtensa/include/asm/thread_info.h +++ b/arch/xtensa/include/asm/thread_info.h @@ -128,19 +128,14 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */ -#define TIF_IRET 4 /* return with iret */ #define TIF_MEMDIE 5 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */ #define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ -#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) -#define _TIF_IRET (1<<TIF_IRET) -#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) -#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #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 */ diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index bc44311aa18c..bc020825cce5 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -328,13 +328,13 @@ long xtensa_execve(const char __user *name, struct pt_regs *regs) { long error; - char * filename; + struct filename *filename; filename = getname(name); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, regs); + error = do_execve(filename->name, argv, envp, regs); putname(filename); out: return error; diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index efe4e854b3cd..63c566f627bc 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -19,7 +19,6 @@ #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/personality.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/ucontext.h> @@ -527,9 +526,6 @@ static void do_signal(struct pt_regs *regs) void do_notify_resume(struct pt_regs *regs) { - if (!user_mode(regs)) - return; - if (test_thread_flag(TIF_SIGPENDING)) do_signal(regs); diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index aab9605f0b43..24ffd8cec51e 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -74,21 +74,21 @@ static inline void netwinder_ds1620_reset(void) static inline void netwinder_lock(unsigned long *flags) { - spin_lock_irqsave(&nw_gpio_lock, *flags); + raw_spin_lock_irqsave(&nw_gpio_lock, *flags); } static inline void netwinder_unlock(unsigned long *flags) { - spin_unlock_irqrestore(&nw_gpio_lock, *flags); + raw_spin_unlock_irqrestore(&nw_gpio_lock, *flags); } static inline void netwinder_set_fan(int i) { unsigned long flags; - spin_lock_irqsave(&nw_gpio_lock, flags); + raw_spin_lock_irqsave(&nw_gpio_lock, flags); nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); - spin_unlock_irqrestore(&nw_gpio_lock, flags); + raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); } static inline int netwinder_get_fan(void) diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index a0e2f7d70355..e371480d3639 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -583,9 +583,9 @@ static void kick_open(void) * we want to write a bit pattern XXX1 to Xilinx to enable * the write gate, which will be open for about the next 2ms. */ - spin_lock_irqsave(&nw_gpio_lock, flags); + raw_spin_lock_irqsave(&nw_gpio_lock, flags); nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); - spin_unlock_irqrestore(&nw_gpio_lock, flags); + raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); /* * let the ISA bus to catch on... diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 65f8e9a54975..1f3417a8322d 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -30,20 +30,12 @@ #include <asm/smp_plat.h> #include <asm/cpu.h> -#include <plat/clock.h> -#include <plat/omap-pm.h> -#include <plat/common.h> -#include <plat/omap_device.h> - -#include <mach/hardware.h> - /* OPP tolerance in percentage */ #define OPP_TOLERANCE 4 static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); static struct clk *mpu_clk; -static char *mpu_clk_name; static struct device *mpu_dev; static struct regulator *mpu_reg; @@ -108,6 +100,14 @@ static int omap_target(struct cpufreq_policy *policy, } freq = freqs.new * 1000; + ret = clk_round_rate(mpu_clk, freq); + if (IS_ERR_VALUE(ret)) { + dev_warn(mpu_dev, + "CPUfreq: Cannot find matching frequency for %lu\n", + freq); + return ret; + } + freq = ret; if (mpu_reg) { opp = opp_find_freq_ceil(mpu_dev, &freq); @@ -172,7 +172,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) { int result = 0; - mpu_clk = clk_get(NULL, mpu_clk_name); + mpu_clk = clk_get(NULL, "cpufreq_ck"); if (IS_ERR(mpu_clk)) return PTR_ERR(mpu_clk); @@ -253,22 +253,10 @@ static struct cpufreq_driver omap_driver = { static int __init omap_cpufreq_init(void) { - if (cpu_is_omap24xx()) - mpu_clk_name = "virt_prcm_set"; - else if (cpu_is_omap34xx()) - mpu_clk_name = "dpll1_ck"; - else if (cpu_is_omap44xx()) - mpu_clk_name = "dpll_mpu_ck"; - - if (!mpu_clk_name) { - pr_err("%s: unsupported Silicon?\n", __func__); - return -EINVAL; - } - - mpu_dev = omap_device_get_by_hwmod_name("mpu"); - if (IS_ERR(mpu_dev)) { + mpu_dev = get_cpu_device(0); + if (!mpu_dev) { pr_warning("%s: unable to get the mpu device\n", __func__); - return PTR_ERR(mpu_dev); + return -EINVAL; } mpu_reg = regulator_get(mpu_dev, "vcc"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a32837951dd2..130a2b510d4a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -19,8 +19,8 @@ #include <linux/clk.h> #include <linux/pm_runtime.h> +#include <video/samsung_fimd.h> #include <drm/exynos_drm.h> -#include <plat/regs-fb-v4.h> #include "exynos_drm_drv.h" #include "exynos_drm_fbdev.h" diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 6f5f98d69af7..f892a424009b 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -46,14 +46,19 @@ static int i2c_debug; #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) #define pca_wait(adap) adap->wait_for_completion(adap->data) -#define pca_reset(adap) adap->reset_chip(adap->data) -static void pca9665_reset(void *pd) +static void pca_reset(struct i2c_algo_pca_data *adap) { - struct i2c_algo_pca_data *adap = pd; - pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); - pca_outw(adap, I2C_PCA_IND, 0xA5); - pca_outw(adap, I2C_PCA_IND, 0x5A); + if (adap->chip == I2C_PCA_CHIP_9665) { + /* Ignore the reset function from the module, + * we can use the parallel bus reset. + */ + pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); + pca_outw(adap, I2C_PCA_IND, 0xA5); + pca_outw(adap, I2C_PCA_IND, 0x5A); + } else { + adap->reset_chip(adap->data); + } } /* @@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap) pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); - return I2C_PCA_CHIP_9665; + pca_data->chip = I2C_PCA_CHIP_9665; } else { printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); - return I2C_PCA_CHIP_9564; + pca_data->chip = I2C_PCA_CHIP_9564; } + return pca_data->chip; } static int pca_init(struct i2c_adapter *adap) @@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap) */ int raise_fall_time; - /* Ignore the reset function from the module, - * we can use the parallel bus reset - */ - pca_data->reset_chip = pca9665_reset; - if (pca_data->i2c_clock > 1265800) { printk(KERN_WARNING "%s: I2C clock speed too high." " Using 1265.8kHz.\n", adap->name); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ff01c389e2da..65dd599a0262 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -294,18 +294,21 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)" config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 && EXPERIMENTAL && BROKEN + depends on ARCH_AT91 && EXPERIMENTAL help This supports the use of the I2C interface on Atmel AT91 processors. - This driver is BROKEN because the controller which it uses - will easily trigger RX overrun and TX underrun errors. Using - low I2C clock rates may partially work around those issues - on some systems. Another serious problem is that there is no - documented way to issue repeated START conditions, as needed + A serious problem is that there is no documented way to issue + repeated START conditions for more than two messages, as needed to support combined I2C messages. Use the i2c-gpio driver - unless your system can cope with those limitations. + unless your system can cope with this limitation. + + Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices + don't have clock stretching in transmission mode. For that reason, + you can encounter underrun issues causing premature stop sendings if + the latency to fill the transmission register is too long. If you + are facing this situation, use the i2c-gpio driver. config I2C_AU1550 tristate "Au1550/Au1200/Au1300 SMBus interface" @@ -718,6 +721,16 @@ config I2C_XLR This driver can also be built as a module. If so, the module will be called i2c-xlr. +config I2C_RCAR + tristate "Renesas R-Car I2C Controller" + depends on ARCH_SHMOBILE && I2C + help + If you say yes to this option, support will be included for the + R-Car I2C controller. + + This driver can also be built as a module. If so, the module + will be called i2c-rcar. + comment "External I2C/SMBus adapter drivers" config I2C_DIOLAN_U2C diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37c4182cc98b..2d33d62952c1 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o +obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index e24484beef07..aa59a254be2c 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -1,315 +1,554 @@ /* - i2c Support for Atmel's AT91 Two-Wire Interface (TWI) - - Copyright (C) 2004 Rick Bronson - Converted to 2.6 by Andrew Victor <andrew@sanpeople.com> - - Borrowed heavily from original work by: - Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. -*/ + * i2c Support for Atmel's AT91 Two-Wire Interface (TWI) + * + * Copyright (C) 2011 Weinmann Medical GmbH + * Author: Nikolaus Voss <n.voss@weinmann.de> + * + * Evolved from original work by: + * Copyright (C) 2004 Rick Bronson + * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com> + * + * Borrowed heavily from original work by: + * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ -#include <linux/module.h> -#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/completion.h> #include <linux/err.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/delay.h> #include <linux/i2c.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_i2c.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */ +#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ + +/* AT91 TWI register definitions */ +#define AT91_TWI_CR 0x0000 /* Control Register */ +#define AT91_TWI_START 0x0001 /* Send a Start Condition */ +#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ +#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ +#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_SWRST 0x0080 /* Software Reset */ + +#define AT91_TWI_MMR 0x0004 /* Master Mode Register */ +#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ +#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */ + +#define AT91_TWI_IADR 0x000c /* Internal Address Register */ + +#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ + +#define AT91_TWI_SR 0x0020 /* Status Register */ +#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */ +#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */ +#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */ -#include <mach/at91_twi.h> -#include <mach/board.h> -#include <mach/cpu.h> +#define AT91_TWI_OVRE 0x0040 /* Overrun Error */ +#define AT91_TWI_UNRE 0x0080 /* Underrun Error */ +#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */ -#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */ +#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */ +#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */ +#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */ +#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */ +#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ +struct at91_twi_pdata { + unsigned clk_max_div; + unsigned clk_offset; + bool has_unre_flag; +}; + +struct at91_twi_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct clk *clk; + u8 *buf; + size_t buf_len; + struct i2c_msg *msg; + int irq; + unsigned transfer_status; + struct i2c_adapter adapter; + unsigned twi_cwgr_reg; + struct at91_twi_pdata *pdata; +}; -static struct clk *twi_clk; -static void __iomem *twi_base; +static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) +{ + return readl_relaxed(dev->base + reg); +} + +static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val) +{ + writel_relaxed(val, dev->base + reg); +} -#define at91_twi_read(reg) __raw_readl(twi_base + (reg)) -#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg)) +static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) +{ + at91_twi_write(dev, AT91_TWI_IDR, + AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); +} +static void at91_init_twi_bus(struct at91_twi_dev *dev) +{ + at91_disable_twi_interrupts(dev); + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN); + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS); + at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg); +} /* - * Initialize the TWI hardware registers. + * Calculate symmetric clock as stated in datasheet: + * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset)) */ -static void __devinit at91_twi_hwinit(void) +static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) { - unsigned long cdiv, ckdiv; - - at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */ - - /* Calcuate clock dividers */ - cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3; - cdiv = cdiv + 1; /* round up */ - ckdiv = 0; - while (cdiv > 255) { - ckdiv++; - cdiv = cdiv >> 1; + int ckdiv, cdiv, div; + struct at91_twi_pdata *pdata = dev->pdata; + int offset = pdata->clk_offset; + int max_ckdiv = pdata->clk_max_div; + + div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk), + 2 * twi_clk) - offset); + ckdiv = fls(div >> 8); + cdiv = div >> ckdiv; + + if (ckdiv > max_ckdiv) { + dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n", + ckdiv, max_ckdiv); + ckdiv = max_ckdiv; + cdiv = 255; } - if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */ - if (ckdiv > 5) { - printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n"); - ckdiv = 5; - } - } + dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv; + dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); +} - at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv); +static void at91_twi_write_next_byte(struct at91_twi_dev *dev) +{ + if (dev->buf_len <= 0) + return; + + at91_twi_write(dev, AT91_TWI_THR, *dev->buf); + + /* send stop when last byte has been written */ + if (--dev->buf_len == 0) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + + dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); + + ++dev->buf; } -/* - * Poll the i2c status register until the specified bit is set. - * Returns 0 if timed out (100 msec). - */ -static short at91_poll_status(unsigned long bit) +static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { - int loop_cntr = 10000; + if (dev->buf_len <= 0) + return; + + *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; + --dev->buf_len; + + /* handle I2C_SMBUS_BLOCK_DATA */ + if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { + dev->msg->flags &= ~I2C_M_RECV_LEN; + dev->buf_len += *dev->buf; + dev->msg->len = dev->buf_len + 1; + dev_dbg(dev->dev, "received block length %d\n", dev->buf_len); + } + + /* send stop if second but last byte has been read */ + if (dev->buf_len == 1) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); - do { - udelay(10); - } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0)); + dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); - return (loop_cntr > 0); + ++dev->buf; } -static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) { - /* Send Start */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_START); - - /* Read data */ - while (length--) { - if (!length) /* need to send Stop before reading last byte */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); - if (!at91_poll_status(AT91_TWI_RXRDY)) { - dev_dbg(&adap->dev, "RXRDY timeout\n"); - return -ETIMEDOUT; - } - *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff); + struct at91_twi_dev *dev = dev_id; + const unsigned status = at91_twi_read(dev, AT91_TWI_SR); + const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR); + + if (!irqstatus) + return IRQ_NONE; + else if (irqstatus & AT91_TWI_RXRDY) + at91_twi_read_next_byte(dev); + else if (irqstatus & AT91_TWI_TXRDY) + at91_twi_write_next_byte(dev); + + /* catch error flags */ + dev->transfer_status |= status; + + if (irqstatus & AT91_TWI_TXCOMP) { + at91_disable_twi_interrupts(dev); + complete(&dev->cmd_complete); } - return 0; + return IRQ_HANDLED; } -static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) +static int at91_do_twi_transfer(struct at91_twi_dev *dev) { - /* Load first byte into transmitter */ - at91_twi_write(AT91_TWI_THR, *buf++); + int ret; + bool has_unre_flag = dev->pdata->has_unre_flag; - /* Send Start */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_START); + dev_dbg(dev->dev, "transfer: %s %d bytes.\n", + (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); - do { - if (!at91_poll_status(AT91_TWI_TXRDY)) { - dev_dbg(&adap->dev, "TXRDY timeout\n"); - return -ETIMEDOUT; - } + INIT_COMPLETION(dev->cmd_complete); + dev->transfer_status = 0; + if (dev->msg->flags & I2C_M_RD) { + unsigned start_flags = AT91_TWI_START; - length--; /* byte was transmitted */ + if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { + dev_err(dev->dev, "RXRDY still set!"); + at91_twi_read(dev, AT91_TWI_RHR); + } - if (length > 0) /* more data to send? */ - at91_twi_write(AT91_TWI_THR, *buf++); - } while (length); + /* if only one byte is to be read, immediately stop transfer */ + if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) + start_flags |= AT91_TWI_STOP; + at91_twi_write(dev, AT91_TWI_CR, start_flags); + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP | AT91_TWI_RXRDY); + } else { + at91_twi_write_next_byte(dev); + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + } - /* Send Stop */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + dev->adapter.timeout); + if (ret == 0) { + dev_err(dev->dev, "controller timed out\n"); + at91_init_twi_bus(dev); + return -ETIMEDOUT; + } + if (dev->transfer_status & AT91_TWI_NACK) { + dev_dbg(dev->dev, "received nack\n"); + return -EREMOTEIO; + } + if (dev->transfer_status & AT91_TWI_OVRE) { + dev_err(dev->dev, "overrun while reading\n"); + return -EIO; + } + if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) { + dev_err(dev->dev, "underrun while writing\n"); + return -EIO; + } + dev_dbg(dev->dev, "transfer complete\n"); return 0; } -/* - * Generic i2c master transfer entrypoint. - * - * Note: We do not use Atmel's feature of storing the "internal device address". - * Instead the "internal device address" has to be written using a separate - * i2c message. - * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html - */ -static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) +static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) { - int i, ret; + struct at91_twi_dev *dev = i2c_get_adapdata(adap); + int ret; + unsigned int_addr_flag = 0; + struct i2c_msg *m_start = msg; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); - for (i = 0; i < num; i++) { - dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, - pmsg->flags & I2C_M_RD ? "read" : "writ", - pmsg->len, pmsg->len > 1 ? "s" : "", - pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); - - at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16) - | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); - - if (pmsg->len && pmsg->buf) { /* sanity check */ - if (pmsg->flags & I2C_M_RD) - ret = xfer_read(adap, pmsg->buf, pmsg->len); - else - ret = xfer_write(adap, pmsg->buf, pmsg->len); - - if (ret) - return ret; - - /* Wait until transfer is finished */ - if (!at91_poll_status(AT91_TWI_TXCOMP)) { - dev_dbg(&adap->dev, "TXCOMP timeout\n"); - return -ETIMEDOUT; - } + /* + * The hardware can handle at most two messages concatenated by a + * repeated start via it's internal address feature. + */ + if (num > 2) { + dev_err(dev->dev, + "cannot handle more than two concatenated messages.\n"); + return 0; + } else if (num == 2) { + int internal_address = 0; + int i; + + if (msg->flags & I2C_M_RD) { + dev_err(dev->dev, "first transfer must be write.\n"); + return -EINVAL; } - dev_dbg(&adap->dev, "transfer complete\n"); - pmsg++; /* next message */ + if (msg->len > 3) { + dev_err(dev->dev, "first message size must be <= 3.\n"); + return -EINVAL; + } + + /* 1st msg is put into the internal address, start with 2nd */ + m_start = &msg[1]; + for (i = 0; i < msg->len; ++i) { + const unsigned addr = msg->buf[msg->len - 1 - i]; + + internal_address |= addr << (8 * i); + int_addr_flag += AT91_TWI_IADRSZ_1; + } + at91_twi_write(dev, AT91_TWI_IADR, internal_address); } - return i; + + at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag + | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + + dev->buf_len = m_start->len; + dev->buf = m_start->buf; + dev->msg = m_start; + + ret = at91_do_twi_transfer(dev); + + return (ret < 0) ? ret : num; } -/* - * Return list of supported functionality. - */ -static u32 at91_func(struct i2c_adapter *adapter) +static u32 at91_twi_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL + | I2C_FUNC_SMBUS_READ_BLOCK_DATA; } -static struct i2c_algorithm at91_algorithm = { - .master_xfer = at91_xfer, - .functionality = at91_func, +static struct i2c_algorithm at91_twi_algorithm = { + .master_xfer = at91_twi_xfer, + .functionality = at91_twi_func, }; -/* - * Main initialization routine. - */ -static int __devinit at91_i2c_probe(struct platform_device *pdev) -{ - struct i2c_adapter *adapter; - struct resource *res; - int rc; +static struct at91_twi_pdata at91rm9200_config = { + .clk_max_div = 5, + .clk_offset = 3, + .has_unre_flag = true, +}; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; +static struct at91_twi_pdata at91sam9261_config = { + .clk_max_div = 5, + .clk_offset = 4, + .has_unre_flag = false, +}; - if (!request_mem_region(res->start, resource_size(res), "at91_i2c")) - return -EBUSY; +static struct at91_twi_pdata at91sam9260_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9g20_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9g10_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; - twi_base = ioremap(res->start, resource_size(res)); - if (!twi_base) { - rc = -ENOMEM; - goto fail0; +static struct at91_twi_pdata at91sam9x5_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + +static const struct platform_device_id at91_twi_devtypes[] = { + { + .name = "i2c-at91rm9200", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "i2c-at91sam9261", + .driver_data = (unsigned long) &at91sam9261_config, + }, { + .name = "i2c-at91sam9260", + .driver_data = (unsigned long) &at91sam9260_config, + }, { + .name = "i2c-at91sam9g20", + .driver_data = (unsigned long) &at91sam9g20_config, + }, { + .name = "i2c-at91sam9g10", + .driver_data = (unsigned long) &at91sam9g10_config, + }, { + /* sentinel */ } +}; - twi_clk = clk_get(NULL, "twi_clk"); - if (IS_ERR(twi_clk)) { - dev_err(&pdev->dev, "no clock defined\n"); - rc = -ENODEV; - goto fail1; +#if defined(CONFIG_OF) +static const struct of_device_id atmel_twi_dt_ids[] = { + { + .compatible = "atmel,at91sam9260-i2c", + .data = &at91sam9260_config, + } , { + .compatible = "atmel,at91sam9g20-i2c", + .data = &at91sam9g20_config, + } , { + .compatible = "atmel,at91sam9g10-i2c", + .data = &at91sam9g10_config, + }, { + .compatible = "atmel,at91sam9x5-i2c", + .data = &at91sam9x5_config, + }, { + /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); +#else +#define atmel_twi_dt_ids NULL +#endif - adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if (adapter == NULL) { - dev_err(&pdev->dev, "can't allocate inteface!\n"); - rc = -ENOMEM; - goto fail2; +static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( + struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node); + if (!match) + return NULL; + return match->data; } - snprintf(adapter->name, sizeof(adapter->name), "AT91"); - adapter->algo = &at91_algorithm; - adapter->class = I2C_CLASS_HWMON; - adapter->dev.parent = &pdev->dev; - /* adapter->id == 0 ... only one TWI controller for now */ + return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data; +} + +static int __devinit at91_twi_probe(struct platform_device *pdev) +{ + struct at91_twi_dev *dev; + struct resource *mem; + int rc; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + init_completion(&dev->cmd_complete); + dev->dev = &pdev->dev; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + + dev->pdata = at91_twi_get_driver_data(pdev); + if (!dev->pdata) + return -ENODEV; - platform_set_drvdata(pdev, adapter); + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) + return -EBUSY; - clk_enable(twi_clk); /* enable peripheral clock */ - at91_twi_hwinit(); /* initialize TWI controller */ + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) + return dev->irq; - rc = i2c_add_numbered_adapter(adapter); + rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0, + dev_name(dev->dev), dev); if (rc) { - dev_err(&pdev->dev, "Adapter %s registration failed\n", - adapter->name); - goto fail3; + dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc); + return rc; } - dev_info(&pdev->dev, "AT91 i2c bus driver.\n"); - return 0; + platform_set_drvdata(pdev, dev); -fail3: - platform_set_drvdata(pdev, NULL); - kfree(adapter); - clk_disable(twi_clk); -fail2: - clk_put(twi_clk); -fail1: - iounmap(twi_base); -fail0: - release_mem_region(res->start, resource_size(res)); + dev->clk = devm_clk_get(dev->dev, NULL); + if (IS_ERR(dev->clk)) { + dev_err(dev->dev, "no clock defined\n"); + return -ENODEV; + } + clk_prepare_enable(dev->clk); + + at91_calc_twi_clock(dev, TWI_CLK_HZ); + at91_init_twi_bus(dev); + + snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); + i2c_set_adapdata(&dev->adapter, dev); + dev->adapter.owner = THIS_MODULE; + dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.algo = &at91_twi_algorithm; + dev->adapter.dev.parent = dev->dev; + dev->adapter.nr = pdev->id; + dev->adapter.timeout = AT91_I2C_TIMEOUT; + dev->adapter.dev.of_node = pdev->dev.of_node; + + rc = i2c_add_numbered_adapter(&dev->adapter); + if (rc) { + dev_err(dev->dev, "Adapter %s registration failed\n", + dev->adapter.name); + clk_disable_unprepare(dev->clk); + return rc; + } - return rc; + of_i2c_register_devices(&dev->adapter); + + dev_info(dev->dev, "AT91 i2c bus driver.\n"); + return 0; } -static int __devexit at91_i2c_remove(struct platform_device *pdev) +static int __devexit at91_twi_remove(struct platform_device *pdev) { - struct i2c_adapter *adapter = platform_get_drvdata(pdev); - struct resource *res; + struct at91_twi_dev *dev = platform_get_drvdata(pdev); int rc; - rc = i2c_del_adapter(adapter); - platform_set_drvdata(pdev, NULL); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iounmap(twi_base); - release_mem_region(res->start, resource_size(res)); - - clk_disable(twi_clk); /* disable peripheral clock */ - clk_put(twi_clk); + rc = i2c_del_adapter(&dev->adapter); + clk_disable_unprepare(dev->clk); return rc; } #ifdef CONFIG_PM -/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */ - -static int at91_i2c_suspend(struct device *dev) +static int at91_twi_runtime_suspend(struct device *dev) { - clk_disable(twi_clk); + struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); + + clk_disable(twi_dev->clk); + return 0; } -static int at91_i2c_resume(struct device *dev) +static int at91_twi_runtime_resume(struct device *dev) { - return clk_enable(twi_clk); + struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); + + return clk_enable(twi_dev->clk); } -static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume); -#define AT91_I2C_PM (&at91_i2c_pm) +static const struct dev_pm_ops at91_twi_pm = { + .runtime_suspend = at91_twi_runtime_suspend, + .runtime_resume = at91_twi_runtime_resume, +}; +#define at91_twi_pm_ops (&at91_twi_pm) #else -#define AT91_I2C_PM NULL +#define at91_twi_pm_ops NULL #endif -static struct platform_driver at91_i2c_driver = { - .probe = at91_i2c_probe, - .remove = __devexit_p(at91_i2c_remove), +static struct platform_driver at91_twi_driver = { + .probe = at91_twi_probe, + .remove = __devexit_p(at91_twi_remove), + .id_table = at91_twi_devtypes, .driver = { .name = "at91_i2c", .owner = THIS_MODULE, - .pm = AT91_I2C_PM, + .of_match_table = atmel_twi_dt_ids, + .pm = at91_twi_pm_ops, }, }; -module_platform_driver(at91_i2c_driver); +static int __init at91_twi_init(void) +{ + return platform_driver_register(&at91_twi_driver); +} + +static void __exit at91_twi_exit(void) +{ + platform_driver_unregister(&at91_twi_driver); +} + +subsys_initcall(at91_twi_init); +module_exit(at91_twi_exit); -MODULE_AUTHOR("Rick Bronson"); +MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>"); MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:at91_i2c"); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 79a2542d8c41..6a0a55319449 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -38,6 +38,8 @@ #include <linux/slab.h> #include <linux/cpufreq.h> #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_device.h> #include <mach/hardware.h> #include <linux/platform_data/i2c-davinci.h> @@ -114,6 +116,7 @@ struct davinci_i2c_dev { struct completion xfr_complete; struct notifier_block freq_transition; #endif + struct davinci_i2c_platform_data *pdata; }; /* default platform data to use if not supplied in the platform_device */ @@ -155,7 +158,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin) static void i2c_recover_bus(struct davinci_i2c_dev *dev) { u32 flag = 0; - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; dev_err(dev->dev, "initiating i2c bus recovery\n"); /* Send NACK to the slave */ @@ -163,8 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev) flag |= DAVINCI_I2C_MDR_NACK; /* write the data into mode register */ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); - if (pdata) - generic_i2c_clock_pulse(pdata->scl_pin); + generic_i2c_clock_pulse(pdata->scl_pin); /* Send STOP */ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); flag |= DAVINCI_I2C_MDR_STP; @@ -187,7 +189,7 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; u16 psc; u32 clk; u32 d; @@ -235,10 +237,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) */ static int i2c_davinci_init(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; - - if (!pdata) - pdata = &davinci_i2c_platform_data_default; + struct davinci_i2c_platform_data *pdata = dev->pdata; /* put I2C into reset */ davinci_i2c_reset_ctrl(dev, 0); @@ -260,6 +259,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n", pdata->bus_freq, pdata->bus_delay); + /* Take the I2C module out of reset: */ davinci_i2c_reset_ctrl(dev, 1); @@ -308,13 +308,11 @@ static int i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; u32 flag; u16 w; int r; - if (!pdata) - pdata = &davinci_i2c_platform_data_default; /* Introduce a delay, required for some boards (e.g Davinci EVM) */ if (pdata->bus_delay) udelay(pdata->bus_delay); @@ -635,6 +633,12 @@ static struct i2c_algorithm i2c_davinci_algo = { .functionality = i2c_davinci_func, }; +static const struct of_device_id davinci_i2c_of_match[] = { + {.compatible = "ti,davinci-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, davinci_i2c_of_match); + static int davinci_i2c_probe(struct platform_device *pdev) { struct davinci_i2c_dev *dev; @@ -674,14 +678,33 @@ static int davinci_i2c_probe(struct platform_device *pdev) #endif dev->dev = get_device(&pdev->dev); dev->irq = irq->start; + dev->pdata = dev->dev->platform_data; platform_set_drvdata(pdev, dev); + if (!dev->pdata && pdev->dev.of_node) { + u32 prop; + + dev->pdata = devm_kzalloc(&pdev->dev, + sizeof(struct davinci_i2c_platform_data), GFP_KERNEL); + if (!dev->pdata) { + r = -ENOMEM; + goto err_free_mem; + } + memcpy(dev->pdata, &davinci_i2c_platform_data_default, + sizeof(struct davinci_i2c_platform_data)); + if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &prop)) + dev->pdata->bus_freq = prop / 1000; + } else if (!dev->pdata) { + dev->pdata = &davinci_i2c_platform_data_default; + } + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { r = -ENODEV; goto err_free_mem; } - clk_enable(dev->clk); + clk_prepare_enable(dev->clk); dev->base = ioremap(mem->start, resource_size(mem)); if (!dev->base) { @@ -711,6 +734,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->algo = &i2c_davinci_algo; adap->dev.parent = &pdev->dev; adap->timeout = DAVINCI_I2C_TIMEOUT; + adap->dev.of_node = pdev->dev.of_node; adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); @@ -718,6 +742,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failure adding adapter\n"); goto err_free_irq; } + of_i2c_register_devices(adap); return 0; @@ -726,7 +751,7 @@ err_free_irq: err_unuse_clocks: iounmap(dev->base); err_mem_ioremap: - clk_disable(dev->clk); + clk_disable_unprepare(dev->clk); clk_put(dev->clk); dev->clk = NULL; err_free_mem: @@ -750,7 +775,7 @@ static int davinci_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); put_device(&pdev->dev); - clk_disable(dev->clk); + clk_disable_unprepare(dev->clk); clk_put(dev->clk); dev->clk = NULL; @@ -772,7 +797,7 @@ static int davinci_i2c_suspend(struct device *dev) /* put I2C into reset */ davinci_i2c_reset_ctrl(i2c_dev, 0); - clk_disable(i2c_dev->clk); + clk_disable_unprepare(i2c_dev->clk); return 0; } @@ -782,7 +807,7 @@ static int davinci_i2c_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - clk_enable(i2c_dev->clk); + clk_prepare_enable(i2c_dev->clk); /* take I2C out of reset */ davinci_i2c_reset_ctrl(i2c_dev, 1); @@ -809,6 +834,7 @@ static struct platform_driver davinci_i2c_driver = { .name = "i2c_davinci", .owner = THIS_MODULE, .pm = davinci_i2c_pm_ops, + .of_match_table = of_match_ptr(davinci_i2c_of_match), }, }; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index b7907ba7448a..2ef162d148cb 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -272,9 +272,9 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, /* dev_dbg() can't be used, because adapter is not yet registered */ #ifdef CONFIG_I2C_DEBUG_BUS - printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n", + dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n", __func__, i2c_clk_rate, div); - printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n", + dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n", __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]); #endif } @@ -564,7 +564,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev) resource_size(res), res->start); dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", i2c_imx->adapter.name); - dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); + dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); return 0; /* Return OK */ } diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 57f7703ce2e8..ca86430cb4a2 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -576,7 +576,23 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); } } - mpc_i2c_stop(i2c); + mpc_i2c_stop(i2c); /* Initiate STOP */ + orig_jiffies = jiffies; + /* Wait until STOP is seen, allow up to 1 s */ + while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { + if (time_after(jiffies, orig_jiffies + HZ)) { + u8 status = readb(i2c->base + MPC_I2C_SR); + + dev_dbg(i2c->dev, "timeout\n"); + if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) { + writeb(status & ~CSR_MAL, + i2c->base + MPC_I2C_SR); + mpc_i2c_fixup(i2c); + } + return -EIO; + } + cond_resched(); + } return (ret < 0) ? ret : num; } diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 51f05b8520ed..1f58197062cf 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -7,8 +7,6 @@ * * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. * - * TODO: add dma-support if platform-support for it is available - * * 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 @@ -31,9 +29,16 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_i2c.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/fsl/mxs-dma.h> #define DRIVER_NAME "mxs-i2c" +static bool use_pioqueue; +module_param(use_pioqueue, bool, 0); +MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA"); + #define MXS_I2C_CTRL0 (0x00) #define MXS_I2C_CTRL0_SET (0x04) @@ -146,6 +151,16 @@ struct mxs_i2c_dev { u32 cmd_err; struct i2c_adapter adapter; const struct mxs_i2c_speed_config *speed; + + /* DMA support components */ + bool dma_mode; + int dma_channel; + struct dma_chan *dmach; + struct mxs_dma_data dma_data; + uint32_t pio_data[2]; + uint32_t addr_data; + struct scatterlist sg_io[2]; + bool dma_read; }; static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) @@ -157,7 +172,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); - writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, + if (i2c->dma_mode) + writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, + i2c->regs + MXS_I2C_QUEUECTRL_CLR); + else + writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, i2c->regs + MXS_I2C_QUEUECTRL_SET); } @@ -248,6 +267,150 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len) return 0; } +static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c) +{ + if (i2c->dma_read) { + dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); + dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); + } else { + dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); + } +} + +static void mxs_i2c_dma_irq_callback(void *param) +{ + struct mxs_i2c_dev *i2c = param; + + complete(&i2c->cmd_complete); + mxs_i2c_dma_finish(i2c); +} + +static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, + struct i2c_msg *msg, uint32_t flags) +{ + struct dma_async_tx_descriptor *desc; + struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); + + if (msg->flags & I2C_M_RD) { + i2c->dma_read = 1; + i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; + + /* + * SELECT command. + */ + + /* Queue the PIO register write transfer. */ + i2c->pio_data[0] = MXS_CMD_I2C_SELECT; + desc = dmaengine_prep_slave_sg(i2c->dmach, + (struct scatterlist *)&i2c->pio_data[0], + 1, DMA_TRANS_NONE, 0); + if (!desc) { + dev_err(i2c->dev, + "Failed to get PIO reg. write descriptor.\n"); + goto select_init_pio_fail; + } + + /* Queue the DMA data transfer. */ + sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1); + dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); + desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(i2c->dev, + "Failed to get DMA data write descriptor.\n"); + goto select_init_dma_fail; + } + + /* + * READ command. + */ + + /* Queue the PIO register write transfer. */ + i2c->pio_data[1] = flags | MXS_CMD_I2C_READ | + MXS_I2C_CTRL0_XFER_COUNT(msg->len); + desc = dmaengine_prep_slave_sg(i2c->dmach, + (struct scatterlist *)&i2c->pio_data[1], + 1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(i2c->dev, + "Failed to get PIO reg. write descriptor.\n"); + goto select_init_dma_fail; + } + + /* Queue the DMA data transfer. */ + sg_init_one(&i2c->sg_io[1], msg->buf, msg->len); + dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); + desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(i2c->dev, + "Failed to get DMA data write descriptor.\n"); + goto read_init_dma_fail; + } + } else { + i2c->dma_read = 0; + i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; + + /* + * WRITE command. + */ + + /* Queue the PIO register write transfer. */ + i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE | + MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1); + desc = dmaengine_prep_slave_sg(i2c->dmach, + (struct scatterlist *)&i2c->pio_data[0], + 1, DMA_TRANS_NONE, 0); + if (!desc) { + dev_err(i2c->dev, + "Failed to get PIO reg. write descriptor.\n"); + goto write_init_pio_fail; + } + + /* Queue the DMA data transfer. */ + sg_init_table(i2c->sg_io, 2); + sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1); + sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len); + dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); + desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(i2c->dev, + "Failed to get DMA data write descriptor.\n"); + goto write_init_dma_fail; + } + } + + /* + * The last descriptor must have this callback, + * to finish the DMA transaction. + */ + desc->callback = mxs_i2c_dma_irq_callback; + desc->callback_param = i2c; + + /* Start the transfer. */ + dmaengine_submit(desc); + dma_async_issue_pending(i2c->dmach); + return 0; + +/* Read failpath. */ +read_init_dma_fail: + dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); +select_init_dma_fail: + dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); +select_init_pio_fail: + return -EINVAL; + +/* Write failpath. */ +write_init_dma_fail: + dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); +write_init_pio_fail: + return -EINVAL; +} + /* * Low level master read/write transaction. */ @@ -258,6 +421,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int ret; int flags; + flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; + dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); @@ -267,23 +432,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, init_completion(&i2c->cmd_complete); i2c->cmd_err = 0; - flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; - - if (msg->flags & I2C_M_RD) - mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags); - else - mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len, - flags); + if (i2c->dma_mode) { + ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); + if (ret) + return ret; + } else { + if (msg->flags & I2C_M_RD) { + mxs_i2c_pioq_setup_read(i2c, msg->addr, + msg->len, flags); + } else { + mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, + msg->len, flags); + } - writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, + writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, i2c->regs + MXS_I2C_QUEUECTRL_SET); + } ret = wait_for_completion_timeout(&i2c->cmd_complete, msecs_to_jiffies(1000)); if (ret == 0) goto timeout; - if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) { + if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) { ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len); if (ret) goto timeout; @@ -301,6 +472,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, timeout: dev_dbg(i2c->dev, "Timeout!\n"); + if (i2c->dma_mode) + mxs_i2c_dma_finish(i2c); mxs_i2c_reset(i2c); return -ETIMEDOUT; } @@ -342,11 +515,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */ i2c->cmd_err = -EIO; - is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & - MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; + if (!i2c->dma_mode) { + is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & + MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; - if (is_last_cmd || i2c->cmd_err) - complete(&i2c->cmd_complete); + if (is_last_cmd || i2c->cmd_err) + complete(&i2c->cmd_complete); + } writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); @@ -358,6 +533,21 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; +static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param) +{ + struct mxs_i2c_dev *i2c = param; + + if (!mxs_dma_is_apbx(chan)) + return false; + + if (chan->chan_id != i2c->dma_channel) + return false; + + chan->private = &i2c->dma_data; + + return true; +} + static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) { uint32_t speed; @@ -365,6 +555,26 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) struct device_node *node = dev->of_node; int ret; + /* + * The MXS I2C DMA mode is prefered and enabled by default. + * The PIO mode is still supported, but should be used only + * for debuging purposes etc. + */ + i2c->dma_mode = !use_pioqueue; + if (!i2c->dma_mode) + dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n"); + + /* + * TODO: This is a temporary solution and should be changed + * to use generic DMA binding later when the helpers get in. + */ + ret = of_property_read_u32(node, "fsl,i2c-dma-channel", + &i2c->dma_channel); + if (ret) { + dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n"); + i2c->dma_mode = 0; + } + ret = of_property_read_u32(node, "clock-frequency", &speed); if (ret) dev_warn(dev, "No I2C speed selected, using 100kHz\n"); @@ -384,7 +594,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) struct pinctrl *pinctrl; struct resource *res; resource_size_t res_size; - int err, irq; + int err, irq, dmairq; + dma_cap_mask_t mask; pinctrl = devm_pinctrl_get_select_default(dev); if (IS_ERR(pinctrl)) @@ -395,7 +606,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + irq = platform_get_irq(pdev, 0); + dmairq = platform_get_irq(pdev, 1); + + if (!res || irq < 0 || dmairq < 0) return -ENOENT; res_size = resource_size(res); @@ -406,10 +620,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) if (!i2c->regs) return -EBUSY; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); if (err) return err; @@ -423,6 +633,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) return err; } + /* Setup the DMA */ + if (i2c->dma_mode) { + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + i2c->dma_data.chan_irq = dmairq; + i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c); + if (!i2c->dmach) { + dev_err(dev, "Failed to request dma\n"); + return -ENODEV; + } + } + platform_set_drvdata(pdev, i2c); /* Do reset to enforce correct startup after pinmuxing */ @@ -458,6 +680,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev) if (ret) return -EBUSY; + if (i2c->dmach) + dma_release_channel(i2c->dmach); + writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); platform_set_drvdata(pdev, NULL); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 61b00edacb08..698d7acb0f08 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -22,9 +22,10 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> #include <linux/platform_data/i2c-nomadik.h> +#include <linux/of.h> +#include <linux/of_i2c.h> #define DRIVER_NAME "nmk-i2c" @@ -146,7 +147,6 @@ struct i2c_nmk_client { * @stop: stop condition. * @xfer_complete: acknowledge completion for a I2C message. * @result: controller propogated result. - * @regulator: pointer to i2c regulator. * @busy: Busy doing transfer. */ struct nmk_i2c_dev { @@ -160,7 +160,6 @@ struct nmk_i2c_dev { int stop; struct completion xfer_complete; int result; - struct regulator *regulator; bool busy; }; @@ -643,8 +642,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, dev->busy = true; - if (dev->regulator) - regulator_enable(dev->regulator); pm_runtime_get_sync(&dev->adev->dev); clk_enable(dev->clk); @@ -676,8 +673,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, out: clk_disable(dev->clk); pm_runtime_put_sync(&dev->adev->dev); - if (dev->regulator) - regulator_disable(dev->regulator); dev->busy = false; @@ -920,18 +915,42 @@ static struct nmk_i2c_controller u8500_i2c = { .sm = I2C_FREQ_MODE_FAST, }; +static void nmk_i2c_of_probe(struct device_node *np, + struct nmk_i2c_controller *pdata) +{ + of_property_read_u32(np, "clock-frequency", &pdata->clk_freq); + + /* This driver only supports 'standard' and 'fast' modes of operation. */ + if (pdata->clk_freq <= 100000) + pdata->sm = I2C_FREQ_MODE_STANDARD; + else + pdata->sm = I2C_FREQ_MODE_FAST; +} + static atomic_t adapter_id = ATOMIC_INIT(0); static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; struct nmk_i2c_controller *pdata = adev->dev.platform_data; + struct device_node *np = adev->dev.of_node; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; - if (!pdata) - /* No i2c configuration found, using the default. */ - pdata = &u8500_i2c; + if (!pdata) { + if (np) { + pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + ret = -ENOMEM; + goto err_no_mem; + } + /* Provide the default configuration as a base. */ + memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller)); + nmk_i2c_of_probe(np, pdata); + } else + /* No i2c configuration found, using the default. */ + pdata = &u8500_i2c; + } dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); if (!dev) { @@ -957,12 +976,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) goto err_irq; } - dev->regulator = regulator_get(&adev->dev, "v-i2c"); - if (IS_ERR(dev->regulator)) { - dev_warn(&adev->dev, "could not get i2c regulator\n"); - dev->regulator = NULL; - } - pm_suspend_ignore_children(&adev->dev, true); dev->clk = clk_get(&adev->dev, NULL); @@ -973,6 +986,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) } adap = &dev->adap; + adap->dev.of_node = np; adap->dev.parent = &adev->dev; adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; @@ -1002,6 +1016,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) goto err_add_adap; } + of_i2c_register_devices(adap); + pm_runtime_put(&adev->dev); return 0; @@ -1009,8 +1025,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) err_add_adap: clk_put(dev->clk); err_no_clk: - if (dev->regulator) - regulator_put(dev->regulator); free_irq(dev->irq, dev); err_irq: iounmap(dev->virtbase); @@ -1038,8 +1052,6 @@ static int nmk_i2c_remove(struct amba_device *adev) if (res) release_mem_region(res->start, resource_size(res)); clk_put(dev->clk); - if (dev->regulator) - regulator_put(dev->regulator); pm_runtime_disable(&adev->dev); amba_set_drvdata(adev, NULL); kfree(dev); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a0e49f6aaf96..db31eaed6ea5 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos.h> /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -55,6 +56,9 @@ /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) +/* timeout for pm runtime autosuspend */ +#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */ + /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ enum { OMAP_I2C_REV_REG = 0, @@ -176,15 +180,15 @@ enum { #define I2C_OMAP_ERRATA_I462 (1 << 1) struct omap_i2c_dev { + spinlock_t lock; /* IRQ synchronization */ struct device *dev; void __iomem *base; /* virtual */ int irq; int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum mpu wkup latency */ - void (*set_mpu_wkup_lat)(struct device *dev, - long latency); + u32 latency; /* maximum MPU wkup latency */ + struct pm_qos_request pm_qos_request; u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -193,12 +197,14 @@ struct omap_i2c_dev { u8 *regs; size_t buf_len; struct i2c_adapter adapter; + u8 threshold; u8 fifo_size; /* use as flag and value * fifo_size==0 implies no fifo * if set, should be trsh+1 */ u8 rev; unsigned b_hw:1; /* bad h/w fixes */ + unsigned receiver:1; /* true when we're in receiver mode */ u16 iestate; /* Saved interrupt register */ u16 pscstate; u16 scllstate; @@ -417,13 +423,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - if (dev->fifo_size) { - /* Note: setup required fifo size - 1. RTRSH and XTRSH */ - buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | - (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); - } - /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); @@ -461,6 +460,43 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) return 0; } +static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +{ + u16 buf; + + if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) + return; + + /* + * Set up notification threshold based on message size. We're doing + * this to try and avoid draining feature as much as possible. Whenever + * we have big messages to transfer (bigger than our total fifo size) + * then we might use draining feature to transfer the remaining bytes. + */ + + dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + + buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + + if (is_rx) { + /* Clear RX Threshold */ + buf &= ~(0x3f << 8); + buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; + } else { + /* Clear TX Threshold */ + buf &= ~0x3f; + buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; + } + + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + dev->b_hw = 1; /* Enable hardware fixes */ + + /* calculate wakeup latency constraint for MPU */ + dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); +} + /* * Low level master read/write transaction. */ @@ -477,6 +513,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (msg->len == 0) return -EINVAL; + dev->receiver = !!(msg->flags & I2C_M_RD); + omap_i2c_resize_fifo(dev, msg->len, dev->receiver); + omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ @@ -590,8 +629,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, dev->latency); + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + */ + if (dev->latency) + pm_qos_add_request(&dev->pm_qos_request, + PM_QOS_CPU_DMA_LATENCY, + dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -599,15 +646,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); + if (dev->latency) + pm_qos_remove_request(&dev->pm_qos_request); if (r == 0) r = num; omap_i2c_wait_for_bb(dev); out: - pm_runtime_put(dev->dev); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); return r; } @@ -725,186 +773,252 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev) { unsigned long timeout = 10000; + u16 stat; - while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { - if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + do { + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (stat & OMAP_I2C_STAT_XUDF) + break; + + if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - return -ETIMEDOUT; + if (stat & OMAP_I2C_STAT_NACK) { + dev->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + + if (stat & OMAP_I2C_STAT_AL) { + dev_err(dev->dev, "Arbitration lost\n"); + dev->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + + return -EIO; } cpu_relax(); - *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } + } while (--timeout); if (!timeout) { dev_err(dev->dev, "timeout waiting on XUDF bit\n"); return 0; } - *err |= OMAP_I2C_STAT_XUDF; return 0; } +static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_rdr) +{ + u16 w; + + while (num_bytes--) { + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } +} + +static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_xdr) +{ + u16 w; + + while (num_bytes--) { + w = *dev->buf++; + dev->buf_len--; + + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + if (ret < 0) + return ret; + } + + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + } + + return 0; +} + +static irqreturn_t +omap_i2c_isr(int irq, void *dev_id) +{ + struct omap_i2c_dev *dev = dev_id; + irqreturn_t ret = IRQ_HANDLED; + u16 mask; + u16 stat; + + spin_lock(&dev->lock); + mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + + if (stat & mask) + ret = IRQ_WAKE_THREAD; + + spin_unlock(&dev->lock); + + return ret; +} + static irqreturn_t -omap_i2c_isr(int this_irq, void *dev_id) +omap_i2c_isr_thread(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; + unsigned long flags; u16 bits; - u16 stat, w; - int err, count = 0; + u16 stat; + int err = 0, count = 0; + + spin_lock_irqsave(&dev->lock, flags); + do { + bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat &= bits; + + /* If we're in receiver mode, ignore XDR/XRDY */ + if (dev->receiver) + stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); + else + stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); - if (pm_runtime_suspended(dev->dev)) - return IRQ_NONE; + if (!stat) { + /* my work here is done */ + goto out; + } - bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) { dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); break; } - err = 0; -complete: - /* - * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be - * acked after the data operation is complete. - * Ref: TRM SWPU114Q Figure 18-31 - */ - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & - ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - - if (stat & OMAP_I2C_STAT_NACK) + if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + break; + } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); + break; } + /* * ProDB0017052: Clear ARDY bit twice */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & - (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR | + OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); + break; } - if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { + + if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1; + if (dev->fifo_size) + num_bytes = dev->buf_len; + + omap_i2c_receive_data(dev, num_bytes, true); + if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); - if (dev->fifo_size) { - if (stat & OMAP_I2C_STAT_RRDY) - num_bytes = dev->fifo_size; - else /* read RXSTAT on RDR interrupt */ - num_bytes = (omap_i2c_read_reg(dev, - OMAP_I2C_BUFSTAT_REG) - >> 8) & 0x3F; - } - while (num_bytes) { - num_bytes--; - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - if (dev->buf_len) { - *dev->buf++ = w; - dev->buf_len--; - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } else { - if (stat & OMAP_I2C_STAT_RRDY) - dev_err(dev->dev, - "RRDY IRQ while no data" - " requested\n"); - if (stat & OMAP_I2C_STAT_RDR) - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); - break; - } - } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + break; + } + + if (stat & OMAP_I2C_STAT_RRDY) { + u8 num_bytes = 1; + + if (dev->threshold) + num_bytes = dev->threshold; + + omap_i2c_receive_data(dev, num_bytes, false); + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); continue; } - if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { + + if (stat & OMAP_I2C_STAT_XDR) { u8 num_bytes = 1; - if (dev->fifo_size) { - if (stat & OMAP_I2C_STAT_XRDY) - num_bytes = dev->fifo_size; - else /* read TXSTAT on XDR interrupt */ - num_bytes = omap_i2c_read_reg(dev, - OMAP_I2C_BUFSTAT_REG) - & 0x3F; - } - while (num_bytes) { - num_bytes--; - w = 0; - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - /* - * Data reg in 2430, omap3 and - * omap4 is 8 bit wide - */ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - } else { - if (stat & OMAP_I2C_STAT_XRDY) - dev_err(dev->dev, - "XRDY IRQ while no " - "data to send\n"); - if (stat & OMAP_I2C_STAT_XDR) - dev_err(dev->dev, - "XDR IRQ while no " - "data to send\n"); - break; - } - - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; - - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); - } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + int ret; + + if (dev->fifo_size) + num_bytes = dev->buf_len; + + ret = omap_i2c_transmit_data(dev, num_bytes, true); + if (ret < 0) + break; + + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); + break; + } + + if (stat & OMAP_I2C_STAT_XRDY) { + u8 num_bytes = 1; + int ret; + + if (dev->threshold) + num_bytes = dev->threshold; + + ret = omap_i2c_transmit_data(dev, num_bytes, false); + if (ret < 0) + break; + + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; } + if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); - dev->cmd_err |= OMAP_I2C_STAT_ROVR; + err |= OMAP_I2C_STAT_ROVR; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + break; } + if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); - dev->cmd_err |= OMAP_I2C_STAT_XUDF; + err |= OMAP_I2C_STAT_XUDF; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + break; } - } + } while (stat); + + omap_i2c_complete_cmd(dev, err); + +out: + spin_unlock_irqrestore(&dev->lock, flags); - return count ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { @@ -943,12 +1057,12 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem; const struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; - irq_handler_t isr; + int irq; int r; /* NOTE: driver uses the static register mapping */ @@ -957,23 +1071,23 @@ omap_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no mem resource?\n"); return -ENODEV; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; + return irq; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; + dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Menory allocation failed\n"); + return -ENOMEM; } - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -ENOMEM; } match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -990,17 +1104,13 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; - dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } dev->dev = &pdev->dev; - dev->irq = irq->start; - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -ENOMEM; - goto err_free_mem; - } + dev->irq = irq; + + spin_lock_init(&dev->lock); platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); @@ -1013,6 +1123,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->regs = (u8 *)reg_map_ip_v1; pm_runtime_enable(dev->dev); + pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(dev->dev); + r = pm_runtime_get_sync(dev->dev); if (IS_ERR_VALUE(r)) goto err_free_mem; @@ -1042,32 +1155,31 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) - dev->b_hw = 0; /* Disable hardware fixes */ - else + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ omap_i2c_init(dev); - isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : - omap_i2c_isr; - r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); + if (dev->rev < OMAP_I2C_OMAP1_REV_2) + r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr, + IRQF_NO_SUSPEND, pdev->name, dev); + else + r = devm_request_threaded_irq(&pdev->dev, dev->irq, + omap_i2c_isr, omap_i2c_isr_thread, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); goto err_unuse_clocks; } - dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, - dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); - adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; @@ -1082,27 +1194,25 @@ omap_i2c_probe(struct platform_device *pdev) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); - goto err_free_irq; + goto err_unuse_clocks; } + dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, + dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + of_i2c_register_devices(adap); - pm_runtime_put(dev->dev); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); return 0; -err_free_irq: - free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); - iounmap(dev->base); pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); return r; } @@ -1110,12 +1220,10 @@ err_release_region: static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; int ret; platform_set_drvdata(pdev, NULL); - free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); if (IS_ERR_VALUE(ret)) @@ -1124,10 +1232,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c new file mode 100644 index 000000000000..f9399d163af2 --- /dev/null +++ b/drivers/i2c/busses/i2c-rcar.c @@ -0,0 +1,709 @@ +/* + * drivers/i2c/busses/i2c-rcar.c + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This file is based on the drivers/i2c/busses/i2c-sh7760.c + * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com> + * + * This file used out-of-tree driver i2c-rcar.c + * Copyright (C) 2011-2012 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/i2c/i2c-rcar.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +/* register offsets */ +#define ICSCR 0x00 /* slave ctrl */ +#define ICMCR 0x04 /* master ctrl */ +#define ICSSR 0x08 /* slave status */ +#define ICMSR 0x0C /* master status */ +#define ICSIER 0x10 /* slave irq enable */ +#define ICMIER 0x14 /* master irq enable */ +#define ICCCR 0x18 /* clock dividers */ +#define ICSAR 0x1C /* slave address */ +#define ICMAR 0x20 /* master address */ +#define ICRXTX 0x24 /* data port */ + +/* ICMCR */ +#define MDBS (1 << 7) /* non-fifo mode switch */ +#define FSCL (1 << 6) /* override SCL pin */ +#define FSDA (1 << 5) /* override SDA pin */ +#define OBPC (1 << 4) /* override pins */ +#define MIE (1 << 3) /* master if enable */ +#define TSBE (1 << 2) +#define FSB (1 << 1) /* force stop bit */ +#define ESG (1 << 0) /* en startbit gen */ + +/* ICMSR */ +#define MNR (1 << 6) /* nack received */ +#define MAL (1 << 5) /* arbitration lost */ +#define MST (1 << 4) /* sent a stop */ +#define MDE (1 << 3) +#define MDT (1 << 2) +#define MDR (1 << 1) +#define MAT (1 << 0) /* slave addr xfer done */ + +/* ICMIE */ +#define MNRE (1 << 6) /* nack irq en */ +#define MALE (1 << 5) /* arblos irq en */ +#define MSTE (1 << 4) /* stop irq en */ +#define MDEE (1 << 3) +#define MDTE (1 << 2) +#define MDRE (1 << 1) +#define MATE (1 << 0) /* address sent irq en */ + + +enum { + RCAR_BUS_PHASE_ADDR, + RCAR_BUS_PHASE_DATA, + RCAR_BUS_PHASE_STOP, +}; + +enum { + RCAR_IRQ_CLOSE, + RCAR_IRQ_OPEN_FOR_SEND, + RCAR_IRQ_OPEN_FOR_RECV, + RCAR_IRQ_OPEN_FOR_STOP, +}; + +/* + * flags + */ +#define ID_LAST_MSG (1 << 0) +#define ID_IOERROR (1 << 1) +#define ID_DONE (1 << 2) +#define ID_ARBLOST (1 << 3) +#define ID_NACK (1 << 4) + +struct rcar_i2c_priv { + void __iomem *io; + struct i2c_adapter adap; + struct i2c_msg *msg; + + spinlock_t lock; + wait_queue_head_t wait; + + int pos; + int irq; + u32 icccr; + u32 flags; +}; + +#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) +#define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD) + +#define rcar_i2c_flags_set(p, f) ((p)->flags |= (f)) +#define rcar_i2c_flags_has(p, f) ((p)->flags & (f)) + +#define LOOP_TIMEOUT 1024 + +/* + * basic functions + */ +static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val) +{ + writel(val, priv->io + reg); +} + +static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) +{ + return readl(priv->io + reg); +} + +static void rcar_i2c_init(struct rcar_i2c_priv *priv) +{ + /* + * reset slave mode. + * slave mode is not used on this driver + */ + rcar_i2c_write(priv, ICSIER, 0); + rcar_i2c_write(priv, ICSAR, 0); + rcar_i2c_write(priv, ICSCR, 0); + rcar_i2c_write(priv, ICSSR, 0); + + /* reset master mode */ + rcar_i2c_write(priv, ICMIER, 0); + rcar_i2c_write(priv, ICMCR, 0); + rcar_i2c_write(priv, ICMSR, 0); + rcar_i2c_write(priv, ICMAR, 0); +} + +static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open) +{ + u32 val = MNRE | MALE | MSTE | MATE; /* default */ + + switch (open) { + case RCAR_IRQ_OPEN_FOR_SEND: + val |= MDEE; /* default + send */ + break; + case RCAR_IRQ_OPEN_FOR_RECV: + val |= MDRE; /* default + read */ + break; + case RCAR_IRQ_OPEN_FOR_STOP: + val = MSTE; /* stop irq only */ + break; + case RCAR_IRQ_CLOSE: + default: + val = 0; /* all close */ + break; + } + rcar_i2c_write(priv, ICMIER, val); +} + +static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv) +{ + rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv); +} + +/* + * bus control functions + */ +static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) +{ + int i; + + for (i = 0; i < LOOP_TIMEOUT; i++) { + /* make sure that bus is not busy */ + if (!(rcar_i2c_read(priv, ICMCR) & FSDA)) + return 0; + udelay(1); + } + + return -EBUSY; +} + +static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase) +{ + switch (phase) { + case RCAR_BUS_PHASE_ADDR: + rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG); + break; + case RCAR_BUS_PHASE_DATA: + rcar_i2c_write(priv, ICMCR, MDBS | MIE); + break; + case RCAR_BUS_PHASE_STOP: + rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB); + break; + } +} + +/* + * clock function + */ +static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, + u32 bus_speed, + struct device *dev) +{ + struct clk *clkp = clk_get(NULL, "peripheral_clk"); + u32 scgd, cdf; + u32 round, ick; + u32 scl; + + if (!clkp) { + dev_err(dev, "there is no peripheral_clk\n"); + return -EIO; + } + + /* + * calculate SCL clock + * see + * ICCCR + * + * ick = clkp / (1 + CDF) + * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick]) + * + * ick : I2C internal clock < 20 MHz + * ticf : I2C SCL falling time = 35 ns here + * tr : I2C SCL rising time = 200 ns here + * intd : LSI internal delay = 50 ns here + * clkp : peripheral_clk + * F[] : integer up-valuation + */ + for (cdf = 0; cdf < 4; cdf++) { + ick = clk_get_rate(clkp) / (1 + cdf); + if (ick < 20000000) + goto ick_find; + } + dev_err(dev, "there is no best CDF\n"); + return -EIO; + +ick_find: + /* + * it is impossible to calculate large scale + * number on u32. separate it + * + * F[(ticf + tr + intd) * ick] + * = F[(35 + 200 + 50)ns * ick] + * = F[285 * ick / 1000000000] + * = F[(ick / 1000000) * 285 / 1000] + */ + round = (ick + 500000) / 1000000 * 285; + round = (round + 500) / 1000; + + /* + * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick]) + * + * Calculation result (= SCL) should be less than + * bus_speed for hardware safety + */ + for (scgd = 0; scgd < 0x40; scgd++) { + scl = ick / (20 + (scgd * 8) + round); + if (scl <= bus_speed) + goto scgd_find; + } + dev_err(dev, "it is impossible to calculate best SCL\n"); + return -EIO; + +scgd_find: + dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n", + scl, bus_speed, clk_get_rate(clkp), round, cdf, scgd); + + /* + * keep icccr value + */ + priv->icccr = (scgd << 2 | cdf); + + return 0; +} + +static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv) +{ + rcar_i2c_write(priv, ICCCR, priv->icccr); +} + +/* + * status functions + */ +static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv) +{ + return rcar_i2c_read(priv, ICMSR); +} + +#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff) +static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit) +{ + rcar_i2c_write(priv, ICMSR, ~bit); +} + +/* + * recv/send functions + */ +static int rcar_i2c_recv(struct rcar_i2c_priv *priv) +{ + rcar_i2c_set_addr(priv, 1); + rcar_i2c_status_clear(priv); + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); + rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV); + + return 0; +} + +static int rcar_i2c_send(struct rcar_i2c_priv *priv) +{ + int ret; + + /* + * It should check bus status when send case + */ + ret = rcar_i2c_bus_barrier(priv); + if (ret < 0) + return ret; + + rcar_i2c_set_addr(priv, 0); + rcar_i2c_status_clear(priv); + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); + rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND); + + return 0; +} + +#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE)) +#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR)) + +/* + * interrupt functions + */ +static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) +{ + struct i2c_msg *msg = priv->msg; + + /* + * FIXME + * sometimes, unknown interrupt happened. + * Do nothing + */ + if (!(msr & MDE)) + return 0; + + /* + * If address transfer phase finished, + * goto data phase. + */ + if (msr & MAT) + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + + if (priv->pos < msg->len) { + /* + * Prepare next data to ICRXTX register. + * This data will go to _SHIFT_ register. + * + * * + * [ICRXTX] -> [SHIFT] -> [I2C bus] + */ + rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]); + priv->pos++; + + } else { + /* + * The last data was pushed to ICRXTX on _PREV_ empty irq. + * It is on _SHIFT_ register, and will sent to I2C bus. + * + * * + * [ICRXTX] -> [SHIFT] -> [I2C bus] + */ + + if (priv->flags & ID_LAST_MSG) + /* + * If current msg is the _LAST_ msg, + * prepare stop condition here. + * ID_DONE will be set on STOP irq. + */ + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + else + /* + * If current msg is _NOT_ last msg, + * it doesn't call stop phase. + * thus, there is no STOP irq. + * return ID_DONE here. + */ + return ID_DONE; + } + + rcar_i2c_send_restart(priv); + + return 0; +} + +static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) +{ + struct i2c_msg *msg = priv->msg; + + /* + * FIXME + * sometimes, unknown interrupt happened. + * Do nothing + */ + if (!(msr & MDR)) + return 0; + + if (msr & MAT) { + /* + * Address transfer phase finished, + * but, there is no data at this point. + * Do nothing. + */ + } else if (priv->pos < msg->len) { + /* + * get received data + */ + msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX); + priv->pos++; + } + + /* + * If next received data is the _LAST_, + * go to STOP phase, + * otherwise, go to DATA phase. + */ + if (priv->pos + 1 >= msg->len) + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + else + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + + rcar_i2c_recv_restart(priv); + + return 0; +} + +static irqreturn_t rcar_i2c_irq(int irq, void *ptr) +{ + struct rcar_i2c_priv *priv = ptr; + struct device *dev = rcar_i2c_priv_to_dev(priv); + u32 msr; + + /*-------------- spin lock -----------------*/ + spin_lock(&priv->lock); + + msr = rcar_i2c_status_get(priv); + + /* + * Arbitration lost + */ + if (msr & MAL) { + /* + * CAUTION + * + * When arbitration lost, device become _slave_ mode. + */ + dev_dbg(dev, "Arbitration Lost\n"); + rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); + goto out; + } + + /* + * Stop + */ + if (msr & MST) { + dev_dbg(dev, "Stop\n"); + rcar_i2c_flags_set(priv, ID_DONE); + goto out; + } + + /* + * Nack + */ + if (msr & MNR) { + dev_dbg(dev, "Nack\n"); + + /* go to stop phase */ + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP); + rcar_i2c_flags_set(priv, ID_NACK); + goto out; + } + + /* + * recv/send + */ + if (rcar_i2c_is_recv(priv)) + rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); + else + rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr)); + +out: + if (rcar_i2c_flags_has(priv, ID_DONE)) { + rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE); + rcar_i2c_status_clear(priv); + wake_up(&priv->wait); + } + + spin_unlock(&priv->lock); + /*-------------- spin unlock -----------------*/ + + return IRQ_HANDLED; +} + +static int rcar_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + struct device *dev = rcar_i2c_priv_to_dev(priv); + unsigned long flags; + int i, ret, timeout; + + pm_runtime_get_sync(dev); + + /*-------------- spin lock -----------------*/ + spin_lock_irqsave(&priv->lock, flags); + + rcar_i2c_init(priv); + rcar_i2c_clock_start(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + /*-------------- spin unlock -----------------*/ + + ret = -EINVAL; + for (i = 0; i < num; i++) { + /*-------------- spin lock -----------------*/ + spin_lock_irqsave(&priv->lock, flags); + + /* init each data */ + priv->msg = &msgs[i]; + priv->pos = 0; + priv->flags = 0; + if (priv->msg == &msgs[num - 1]) + rcar_i2c_flags_set(priv, ID_LAST_MSG); + + /* start send/recv */ + if (rcar_i2c_is_recv(priv)) + ret = rcar_i2c_recv(priv); + else + ret = rcar_i2c_send(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + /*-------------- spin unlock -----------------*/ + + if (ret < 0) + break; + + /* + * wait result + */ + timeout = wait_event_timeout(priv->wait, + rcar_i2c_flags_has(priv, ID_DONE), + 5 * HZ); + if (!timeout) { + ret = -ETIMEDOUT; + break; + } + + /* + * error handling + */ + if (rcar_i2c_flags_has(priv, ID_NACK)) { + ret = -EREMOTEIO; + break; + } + + if (rcar_i2c_flags_has(priv, ID_ARBLOST)) { + ret = -EAGAIN; + break; + } + + if (rcar_i2c_flags_has(priv, ID_IOERROR)) { + ret = -EIO; + break; + } + + ret = i + 1; /* The number of transfer */ + } + + pm_runtime_put(dev); + + if (ret < 0) + dev_err(dev, "error %d : %x\n", ret, priv->flags); + + return ret; +} + +static u32 rcar_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm rcar_i2c_algo = { + .master_xfer = rcar_i2c_master_xfer, + .functionality = rcar_i2c_func, +}; + +static int __devinit rcar_i2c_probe(struct platform_device *pdev) +{ + struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data; + struct rcar_i2c_priv *priv; + struct i2c_adapter *adap; + struct resource *res; + struct device *dev = &pdev->dev; + u32 bus_speed; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no mmio resources\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); + if (!priv) { + dev_err(dev, "no mem for private data\n"); + return -ENOMEM; + } + + bus_speed = 100000; /* default 100 kHz */ + if (pdata && pdata->bus_speed) + bus_speed = pdata->bus_speed; + ret = rcar_i2c_clock_calculate(priv, bus_speed, dev); + if (ret < 0) + return ret; + + priv->io = devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->io) { + dev_err(dev, "cannot ioremap\n"); + return -ENODEV; + } + + priv->irq = platform_get_irq(pdev, 0); + init_waitqueue_head(&priv->wait); + spin_lock_init(&priv->lock); + + adap = &priv->adap; + adap->nr = pdev->id; + adap->algo = &rcar_i2c_algo; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->retries = 3; + adap->dev.parent = dev; + i2c_set_adapdata(adap, priv); + strlcpy(adap->name, pdev->name, sizeof(adap->name)); + + ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, + dev_name(dev), priv); + if (ret < 0) { + dev_err(dev, "cannot get irq %d\n", priv->irq); + return ret; + } + + ret = i2c_add_numbered_adapter(adap); + if (ret < 0) { + dev_err(dev, "reg adap failed: %d\n", ret); + return ret; + } + + pm_runtime_enable(dev); + platform_set_drvdata(pdev, priv); + + dev_info(dev, "probed\n"); + + return 0; +} + +static int __devexit rcar_i2c_remove(struct platform_device *pdev) +{ + struct rcar_i2c_priv *priv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + i2c_del_adapter(&priv->adap); + pm_runtime_disable(dev); + + return 0; +} + +static struct platform_driver rcar_i2c_drv = { + .driver = { + .name = "i2c-rcar", + .owner = THIS_MODULE, + }, + .probe = rcar_i2c_probe, + .remove = __devexit_p(rcar_i2c_remove), +}; + +module_platform_driver(rcar_i2c_drv); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Renesas R-Car I2C bus driver"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4d07dea9bca9..3e0335f1fc60 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -601,14 +601,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, int ret; pm_runtime_get_sync(&adap->dev); - clk_enable(i2c->clk); + clk_prepare_enable(i2c->clk); for (retry = 0; retry < adap->retries; retry++) { ret = s3c24xx_i2c_doxfer(i2c, msgs, num); if (ret != -EAGAIN) { - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); pm_runtime_put(&adap->dev); return ret; } @@ -618,7 +618,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, udelay(100); } - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); pm_runtime_put(&adap->dev); return -EREMOTEIO; } @@ -977,7 +977,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); - clk_enable(i2c->clk); + clk_prepare_enable(i2c->clk); /* map the registers */ @@ -1065,7 +1065,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) pm_runtime_enable(&i2c->adap.dev); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); return 0; err_cpufreq: @@ -1082,7 +1082,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) kfree(i2c->ioarea); err_clk: - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); err_noclk: @@ -1106,7 +1106,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); free_irq(i2c->irq, i2c); - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); iounmap(i2c->regs); @@ -1135,9 +1135,9 @@ static int s3c24xx_i2c_resume(struct device *dev) struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); i2c->suspended = 0; - clk_enable(i2c->clk); + clk_prepare_enable(i2c->clk); s3c24xx_i2c_init(i2c); - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); return 0; } diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 118d0300f1fb..6ae2ac47c9c8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -23,11 +23,11 @@ #include <linux/input/mt.h> #include <linux/major.h> #include <linux/device.h> +#include <linux/cdev.h> #include "input-compat.h" struct evdev { int open; - int minor; struct input_handle handle; wait_queue_head_t wait; struct evdev_client __rcu *grab; @@ -35,6 +35,7 @@ struct evdev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + struct cdev cdev; bool exist; }; @@ -51,9 +52,6 @@ struct evdev_client { struct input_event buffer[]; }; -static struct evdev *evdev_table[EVDEV_MINORS]; -static DEFINE_MUTEX(evdev_table_mutex); - static void __pass_event(struct evdev_client *client, const struct input_event *event) { @@ -310,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev) static int evdev_open(struct inode *inode, struct file *file) { - struct evdev *evdev; + struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); + unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); struct evdev_client *client; - int i = iminor(inode) - EVDEV_MINOR_BASE; - unsigned int bufsize; int error; - if (i >= EVDEV_MINORS) - return -ENODEV; - - error = mutex_lock_interruptible(&evdev_table_mutex); - if (error) - return error; - evdev = evdev_table[i]; - if (evdev) - get_device(&evdev->dev); - mutex_unlock(&evdev_table_mutex); - - if (!evdev) - return -ENODEV; - - bufsize = evdev_compute_buffer_size(evdev->handle.dev); - client = kzalloc(sizeof(struct evdev_client) + bufsize * sizeof(struct input_event), GFP_KERNEL); - if (!client) { - error = -ENOMEM; - goto err_put_evdev; - } + if (!client) + return -ENOMEM; client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); @@ -352,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file) file->private_data = client; nonseekable_open(inode, file); + get_device(&evdev->dev); return 0; err_free_client: evdev_detach_client(evdev, client); kfree(client); - err_put_evdev: - put_device(&evdev->dev); return error; } @@ -942,26 +920,6 @@ static const struct file_operations evdev_fops = { .llseek = no_llseek, }; -static int evdev_install_chrdev(struct evdev *evdev) -{ - /* - * No need to do any locking here as calls to connect and - * disconnect are serialized by the input core - */ - evdev_table[evdev->minor] = evdev; - return 0; -} - -static void evdev_remove_chrdev(struct evdev *evdev) -{ - /* - * Lock evdev table to prevent race with evdev_open() - */ - mutex_lock(&evdev_table_mutex); - evdev_table[evdev->minor] = NULL; - mutex_unlock(&evdev_table_mutex); -} - /* * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted @@ -980,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev) evdev_mark_dead(evdev); evdev_hangup(evdev); - evdev_remove_chrdev(evdev); + + cdev_del(&evdev->cdev); /* evdev is marked dead so no one else accesses evdev->open */ if (evdev->open) { @@ -991,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev) /* * Create new evdev device. Note that input core serializes calls - * to connect and disconnect so we don't need to lock evdev_table here. + * to connect and disconnect. */ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct evdev *evdev; int minor; + int dev_no; int error; - for (minor = 0; minor < EVDEV_MINORS; minor++) - if (!evdev_table[minor]) - break; - - if (minor == EVDEV_MINORS) { - pr_err("no more free evdev devices\n"); - return -ENFILE; + minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); + if (minor < 0) { + error = minor; + pr_err("failed to reserve new minor: %d\n", error); + return error; } evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); - if (!evdev) - return -ENOMEM; + if (!evdev) { + error = -ENOMEM; + goto err_free_minor; + } INIT_LIST_HEAD(&evdev->client_list); spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); - - dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = true; - evdev->minor = minor; + + dev_no = minor; + /* Normalize device number if it falls into legacy range */ + if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) + dev_no -= EVDEV_MINOR_BASE; + dev_set_name(&evdev->dev, "event%d", dev_no); evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; - evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); + evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; evdev->dev.release = evdev_free; @@ -1037,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, if (error) goto err_free_evdev; - error = evdev_install_chrdev(evdev); + cdev_init(&evdev->cdev, &evdev_fops); + error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); if (error) goto err_unregister_handle; @@ -1053,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); + err_free_minor: + input_free_minor(minor); return error; } @@ -1062,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle) device_del(&evdev->dev); evdev_cleanup(evdev); + input_free_minor(MINOR(evdev->dev.devt)); input_unregister_handle(handle); put_device(&evdev->dev); } @@ -1078,7 +1045,7 @@ static struct input_handler evdev_handler = { .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect, - .fops = &evdev_fops, + .legacy_minors = true, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, diff --git a/drivers/input/input.c b/drivers/input/input.c index ace3f7c4226d..53a0ddee7872 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/types.h> +#include <linux/idr.h> #include <linux/input/mt.h> #include <linux/module.h> #include <linux/slab.h> @@ -32,7 +33,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("Input core"); MODULE_LICENSE("GPL"); -#define INPUT_DEVICES 256 +#define INPUT_MAX_CHAR_DEVICES 1024 +#define INPUT_FIRST_DYNAMIC_DEV 256 +static DEFINE_IDA(input_ida); static LIST_HEAD(input_dev_list); static LIST_HEAD(input_handler_list); @@ -45,8 +48,6 @@ static LIST_HEAD(input_handler_list); */ static DEFINE_MUTEX(input_mutex); -static struct input_handler *input_table[8]; - static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; static inline int is_event_supported(unsigned int code, @@ -1218,7 +1219,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); if (handler->filter) seq_puts(seq, " (filter)"); - if (handler->fops) + if (handler->legacy_minors) seq_printf(seq, " Minor=%d", handler->minor); seq_putc(seq, '\n'); @@ -2016,22 +2017,14 @@ EXPORT_SYMBOL(input_unregister_device); int input_register_handler(struct input_handler *handler) { struct input_dev *dev; - int retval; + int error; - retval = mutex_lock_interruptible(&input_mutex); - if (retval) - return retval; + error = mutex_lock_interruptible(&input_mutex); + if (error) + return error; INIT_LIST_HEAD(&handler->h_list); - if (handler->fops != NULL) { - if (input_table[handler->minor >> 5]) { - retval = -EBUSY; - goto out; - } - input_table[handler->minor >> 5] = handler; - } - list_add_tail(&handler->node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) @@ -2039,9 +2032,8 @@ int input_register_handler(struct input_handler *handler) input_wakeup_procfs_readers(); - out: mutex_unlock(&input_mutex); - return retval; + return 0; } EXPORT_SYMBOL(input_register_handler); @@ -2064,9 +2056,6 @@ void input_unregister_handler(struct input_handler *handler) list_del_init(&handler->node); - if (handler->fops != NULL) - input_table[handler->minor >> 5] = NULL; - input_wakeup_procfs_readers(); mutex_unlock(&input_mutex); @@ -2183,51 +2172,52 @@ void input_unregister_handle(struct input_handle *handle) } EXPORT_SYMBOL(input_unregister_handle); -static int input_open_file(struct inode *inode, struct file *file) +/** + * input_get_new_minor - allocates a new input minor number + * @legacy_base: beginning or the legacy range to be searched + * @legacy_num: size of legacy range + * @allow_dynamic: whether we can also take ID from the dynamic range + * + * This function allocates a new device minor for from input major namespace. + * Caller can request legacy minor by specifying @legacy_base and @legacy_num + * parameters and whether ID can be allocated from dynamic range if there are + * no free IDs in legacy range. + */ +int input_get_new_minor(int legacy_base, unsigned int legacy_num, + bool allow_dynamic) { - struct input_handler *handler; - const struct file_operations *old_fops, *new_fops = NULL; - int err; - - err = mutex_lock_interruptible(&input_mutex); - if (err) - return err; - - /* No load-on-demand here? */ - handler = input_table[iminor(inode) >> 5]; - if (handler) - new_fops = fops_get(handler->fops); - - mutex_unlock(&input_mutex); - /* - * That's _really_ odd. Usually NULL ->open means "nothing special", - * not "no device". Oh, well... + * This function should be called from input handler's ->connect() + * methods, which are serialized with input_mutex, so no additional + * locking is needed here. */ - if (!new_fops || !new_fops->open) { - fops_put(new_fops); - err = -ENODEV; - goto out; + if (legacy_base >= 0) { + int minor = ida_simple_get(&input_ida, + legacy_base, + legacy_base + legacy_num, + GFP_KERNEL); + if (minor >= 0 || !allow_dynamic) + return minor; } - old_fops = file->f_op; - file->f_op = new_fops; - - err = new_fops->open(inode, file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); -out: - return err; + return ida_simple_get(&input_ida, + INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES, + GFP_KERNEL); } +EXPORT_SYMBOL(input_get_new_minor); -static const struct file_operations input_fops = { - .owner = THIS_MODULE, - .open = input_open_file, - .llseek = noop_llseek, -}; +/** + * input_free_minor - release previously allocated minor + * @minor: minor to be released + * + * This function releases previously allocated input minor so that it can be + * reused later. + */ +void input_free_minor(unsigned int minor) +{ + ida_simple_remove(&input_ida, minor); +} +EXPORT_SYMBOL(input_free_minor); static int __init input_init(void) { @@ -2243,7 +2233,8 @@ static int __init input_init(void) if (err) goto fail1; - err = register_chrdev(INPUT_MAJOR, "input", &input_fops); + err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), + INPUT_MAX_CHAR_DEVICES, "input"); if (err) { pr_err("unable to register char major %d", INPUT_MAJOR); goto fail2; @@ -2259,7 +2250,8 @@ static int __init input_init(void) static void __exit input_exit(void) { input_proc_exit(); - unregister_chrdev(INPUT_MAJOR, "input"); + unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0), + INPUT_MAX_CHAR_DEVICES); class_unregister(&input_class); } diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 78f323ea1e4b..b62b5891f399 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -27,6 +27,7 @@ #include <linux/poll.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/cdev.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Joystick device interfaces"); @@ -39,13 +40,13 @@ MODULE_LICENSE("GPL"); struct joydev { int open; - int minor; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + struct cdev cdev; bool exist; struct js_corr corr[ABS_CNT]; @@ -70,9 +71,6 @@ struct joydev_client { struct list_head node; }; -static struct joydev *joydev_table[JOYDEV_MINORS]; -static DEFINE_MUTEX(joydev_table_mutex); - static int joydev_correct(int value, struct js_corr *corr) { switch (corr->type) { @@ -252,30 +250,14 @@ static int joydev_release(struct inode *inode, struct file *file) static int joydev_open(struct inode *inode, struct file *file) { + struct joydev *joydev = + container_of(inode->i_cdev, struct joydev, cdev); struct joydev_client *client; - struct joydev *joydev; - int i = iminor(inode) - JOYDEV_MINOR_BASE; int error; - if (i >= JOYDEV_MINORS) - return -ENODEV; - - error = mutex_lock_interruptible(&joydev_table_mutex); - if (error) - return error; - joydev = joydev_table[i]; - if (joydev) - get_device(&joydev->dev); - mutex_unlock(&joydev_table_mutex); - - if (!joydev) - return -ENODEV; - client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); - if (!client) { - error = -ENOMEM; - goto err_put_joydev; - } + if (!client) + return -ENOMEM; spin_lock_init(&client->buffer_lock); client->joydev = joydev; @@ -288,13 +270,12 @@ static int joydev_open(struct inode *inode, struct file *file) file->private_data = client; nonseekable_open(inode, file); + get_device(&joydev->dev); return 0; err_free_client: joydev_detach_client(joydev, client); kfree(client); - err_put_joydev: - put_device(&joydev->dev); return error; } @@ -742,19 +723,6 @@ static const struct file_operations joydev_fops = { .llseek = no_llseek, }; -static int joydev_install_chrdev(struct joydev *joydev) -{ - joydev_table[joydev->minor] = joydev; - return 0; -} - -static void joydev_remove_chrdev(struct joydev *joydev) -{ - mutex_lock(&joydev_table_mutex); - joydev_table[joydev->minor] = NULL; - mutex_unlock(&joydev_table_mutex); -} - /* * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted @@ -773,7 +741,8 @@ static void joydev_cleanup(struct joydev *joydev) joydev_mark_dead(joydev); joydev_hangup(joydev); - joydev_remove_chrdev(joydev); + + cdev_del(&joydev->cdev); /* joydev is marked dead so no one else accesses joydev->open */ if (joydev->open) @@ -798,30 +767,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct joydev *joydev; - int i, j, t, minor; + int i, j, t, minor, dev_no; int error; - for (minor = 0; minor < JOYDEV_MINORS; minor++) - if (!joydev_table[minor]) - break; - - if (minor == JOYDEV_MINORS) { - pr_err("no more free joydev devices\n"); - return -ENFILE; + minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true); + if (minor < 0) { + error = minor; + pr_err("failed to reserve new minor: %d\n", error); + return error; } joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); - if (!joydev) - return -ENOMEM; + if (!joydev) { + error = -ENOMEM; + goto err_free_minor; + } INIT_LIST_HEAD(&joydev->client_list); spin_lock_init(&joydev->client_lock); mutex_init(&joydev->mutex); init_waitqueue_head(&joydev->wait); - - dev_set_name(&joydev->dev, "js%d", minor); joydev->exist = true; - joydev->minor = minor; + + dev_no = minor; + /* Normalize device number if it falls into legacy range */ + if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS) + dev_no -= JOYDEV_MINOR_BASE; + dev_set_name(&joydev->dev, "js%d", dev_no); joydev->handle.dev = input_get_device(dev); joydev->handle.name = dev_name(&joydev->dev); @@ -875,7 +847,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, } } - joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); + joydev->dev.devt = MKDEV(INPUT_MAJOR, minor); joydev->dev.class = &input_class; joydev->dev.parent = &dev->dev; joydev->dev.release = joydev_free; @@ -885,7 +857,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, if (error) goto err_free_joydev; - error = joydev_install_chrdev(joydev); + cdev_init(&joydev->cdev, &joydev_fops); + error = cdev_add(&joydev->cdev, joydev->dev.devt, 1); if (error) goto err_unregister_handle; @@ -901,6 +874,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, input_unregister_handle(&joydev->handle); err_free_joydev: put_device(&joydev->dev); + err_free_minor: + input_free_minor(minor); return error; } @@ -910,6 +885,7 @@ static void joydev_disconnect(struct input_handle *handle) device_del(&joydev->dev); joydev_cleanup(joydev); + input_free_minor(MINOR(joydev->dev.devt)); input_unregister_handle(handle); put_device(&joydev->dev); } @@ -961,7 +937,7 @@ static struct input_handler joydev_handler = { .match = joydev_match, .connect = joydev_connect, .disconnect = joydev_disconnect, - .fops = &joydev_fops, + .legacy_minors = true, .minor = JOYDEV_MINOR_BASE, .name = "joydev", .id_table = joydev_ids, diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 277e26dc910e..9d7a111486f7 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -431,6 +431,12 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) goto err_unmap_base; } + error = clk_prepare(keypad->clk); + if (error) { + dev_err(&pdev->dev, "keypad clock prepare failed\n"); + goto err_put_clk; + } + keypad->input_dev = input_dev; keypad->pdev = pdev; keypad->row_shift = row_shift; @@ -461,7 +467,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) keypad->keycodes, input_dev); if (error) { dev_err(&pdev->dev, "failed to build keymap\n"); - goto err_put_clk; + goto err_unprepare_clk; } input_set_capability(input_dev, EV_MSC, MSC_SCAN); @@ -503,6 +509,8 @@ err_free_irq: pm_runtime_disable(&pdev->dev); device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); +err_unprepare_clk: + clk_unprepare(keypad->clk); err_put_clk: clk_put(keypad->clk); samsung_keypad_dt_gpio_free(keypad); @@ -531,6 +539,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev) */ free_irq(keypad->irq, keypad); + clk_unprepare(keypad->clk); clk_put(keypad->clk); samsung_keypad_dt_gpio_free(keypad); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 964e43d81e29..a1b4c37956b2 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -24,10 +24,8 @@ #include <linux/random.h> #include <linux/major.h> #include <linux/device.h> +#include <linux/cdev.h> #include <linux/kernel.h> -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX -#include <linux/miscdevice.h> -#endif MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); @@ -61,17 +59,18 @@ struct mousedev_hw_data { struct mousedev { int open; - int minor; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + struct cdev cdev; bool exist; + bool is_mixdev; struct list_head mixdev_node; - int mixdev_open; + bool opened_by_mixdev; struct mousedev_hw_data packet; unsigned int pkt_count; @@ -114,10 +113,6 @@ struct mousedev_client { static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; -static struct input_handler mousedev_handler; - -static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; -static DEFINE_MUTEX(mousedev_table_mutex); static struct mousedev *mousedev_mix; static LIST_HEAD(mousedev_mix_list); @@ -433,7 +428,7 @@ static int mousedev_open_device(struct mousedev *mousedev) if (retval) return retval; - if (mousedev->minor == MOUSEDEV_MIX) + if (mousedev->is_mixdev) mixdev_open_devices(); else if (!mousedev->exist) retval = -ENODEV; @@ -451,7 +446,7 @@ static void mousedev_close_device(struct mousedev *mousedev) { mutex_lock(&mousedev->mutex); - if (mousedev->minor == MOUSEDEV_MIX) + if (mousedev->is_mixdev) mixdev_close_devices(); else if (mousedev->exist && !--mousedev->open) input_close_device(&mousedev->handle); @@ -472,11 +467,11 @@ static void mixdev_open_devices(void) return; list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { - if (!mousedev->mixdev_open) { + if (!mousedev->opened_by_mixdev) { if (mousedev_open_device(mousedev)) continue; - mousedev->mixdev_open = 1; + mousedev->opened_by_mixdev = true; } } } @@ -494,8 +489,8 @@ static void mixdev_close_devices(void) return; list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { - if (mousedev->mixdev_open) { - mousedev->mixdev_open = 0; + if (mousedev->opened_by_mixdev) { + mousedev->opened_by_mixdev = false; mousedev_close_device(mousedev); } } @@ -538,35 +533,17 @@ static int mousedev_open(struct inode *inode, struct file *file) struct mousedev_client *client; struct mousedev *mousedev; int error; - int i; #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX if (imajor(inode) == MISC_MAJOR) - i = MOUSEDEV_MIX; + mousedev = mousedev_mix; else #endif - i = iminor(inode) - MOUSEDEV_MINOR_BASE; - - if (i >= MOUSEDEV_MINORS) - return -ENODEV; - - error = mutex_lock_interruptible(&mousedev_table_mutex); - if (error) - return error; - - mousedev = mousedev_table[i]; - if (mousedev) - get_device(&mousedev->dev); - mutex_unlock(&mousedev_table_mutex); - - if (!mousedev) - return -ENODEV; + mousedev = container_of(inode->i_cdev, struct mousedev, cdev); client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); - if (!client) { - error = -ENOMEM; - goto err_put_mousedev; - } + if (!client) + return -ENOMEM; spin_lock_init(&client->packet_lock); client->pos_x = xres / 2; @@ -579,13 +556,14 @@ static int mousedev_open(struct inode *inode, struct file *file) goto err_free_client; file->private_data = client; + nonseekable_open(inode, file); + + get_device(&mousedev->dev); return 0; err_free_client: mousedev_detach_client(mousedev, client); kfree(client); - err_put_mousedev: - put_device(&mousedev->dev); return error; } @@ -785,29 +763,16 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait) } static const struct file_operations mousedev_fops = { - .owner = THIS_MODULE, - .read = mousedev_read, - .write = mousedev_write, - .poll = mousedev_poll, - .open = mousedev_open, - .release = mousedev_release, - .fasync = mousedev_fasync, - .llseek = noop_llseek, + .owner = THIS_MODULE, + .read = mousedev_read, + .write = mousedev_write, + .poll = mousedev_poll, + .open = mousedev_open, + .release = mousedev_release, + .fasync = mousedev_fasync, + .llseek = noop_llseek, }; -static int mousedev_install_chrdev(struct mousedev *mousedev) -{ - mousedev_table[mousedev->minor] = mousedev; - return 0; -} - -static void mousedev_remove_chrdev(struct mousedev *mousedev) -{ - mutex_lock(&mousedev_table_mutex); - mousedev_table[mousedev->minor] = NULL; - mutex_unlock(&mousedev_table_mutex); -} - /* * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted @@ -842,24 +807,50 @@ static void mousedev_cleanup(struct mousedev *mousedev) mousedev_mark_dead(mousedev); mousedev_hangup(mousedev); - mousedev_remove_chrdev(mousedev); + + cdev_del(&mousedev->cdev); /* mousedev is marked dead so no one else accesses mousedev->open */ if (mousedev->open) input_close_device(handle); } +static int mousedev_reserve_minor(bool mixdev) +{ + int minor; + + if (mixdev) { + minor = input_get_new_minor(MOUSEDEV_MIX, 1, false); + if (minor < 0) + pr_err("failed to reserve mixdev minor: %d\n", minor); + } else { + minor = input_get_new_minor(MOUSEDEV_MINOR_BASE, + MOUSEDEV_MINORS, true); + if (minor < 0) + pr_err("failed to reserve new minor: %d\n", minor); + } + + return minor; +} + static struct mousedev *mousedev_create(struct input_dev *dev, struct input_handler *handler, - int minor) + bool mixdev) { struct mousedev *mousedev; + int minor; int error; + minor = mousedev_reserve_minor(mixdev); + if (minor < 0) { + error = minor; + goto err_out; + } + mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); if (!mousedev) { error = -ENOMEM; - goto err_out; + goto err_free_minor; } INIT_LIST_HEAD(&mousedev->client_list); @@ -867,16 +858,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev, spin_lock_init(&mousedev->client_lock); mutex_init(&mousedev->mutex); lockdep_set_subclass(&mousedev->mutex, - minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0); + mixdev ? SINGLE_DEPTH_NESTING : 0); init_waitqueue_head(&mousedev->wait); - if (minor == MOUSEDEV_MIX) + if (mixdev) { dev_set_name(&mousedev->dev, "mice"); - else - dev_set_name(&mousedev->dev, "mouse%d", minor); + } else { + int dev_no = minor; + /* Normalize device number if it falls into legacy range */ + if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) + dev_no -= MOUSEDEV_MINOR_BASE; + dev_set_name(&mousedev->dev, "mouse%d", dev_no); + } - mousedev->minor = minor; mousedev->exist = true; + mousedev->is_mixdev = mixdev; mousedev->handle.dev = input_get_device(dev); mousedev->handle.name = dev_name(&mousedev->dev); mousedev->handle.handler = handler; @@ -885,17 +881,18 @@ static struct mousedev *mousedev_create(struct input_dev *dev, mousedev->dev.class = &input_class; if (dev) mousedev->dev.parent = &dev->dev; - mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); + mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor); mousedev->dev.release = mousedev_free; device_initialize(&mousedev->dev); - if (minor != MOUSEDEV_MIX) { + if (!mixdev) { error = input_register_handle(&mousedev->handle); if (error) goto err_free_mousedev; } - error = mousedev_install_chrdev(mousedev); + cdev_init(&mousedev->cdev, &mousedev_fops); + error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1); if (error) goto err_unregister_handle; @@ -908,10 +905,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev, err_cleanup_mousedev: mousedev_cleanup(mousedev); err_unregister_handle: - if (minor != MOUSEDEV_MIX) + if (!mixdev) input_unregister_handle(&mousedev->handle); err_free_mousedev: put_device(&mousedev->dev); + err_free_minor: + input_free_minor(minor); err_out: return ERR_PTR(error); } @@ -920,7 +919,8 @@ static void mousedev_destroy(struct mousedev *mousedev) { device_del(&mousedev->dev); mousedev_cleanup(mousedev); - if (mousedev->minor != MOUSEDEV_MIX) + input_free_minor(MINOR(mousedev->dev.devt)); + if (!mousedev->is_mixdev) input_unregister_handle(&mousedev->handle); put_device(&mousedev->dev); } @@ -938,7 +938,7 @@ static int mixdev_add_device(struct mousedev *mousedev) if (retval) goto out; - mousedev->mixdev_open = 1; + mousedev->opened_by_mixdev = true; } get_device(&mousedev->dev); @@ -953,8 +953,8 @@ static void mixdev_remove_device(struct mousedev *mousedev) { mutex_lock(&mousedev_mix->mutex); - if (mousedev->mixdev_open) { - mousedev->mixdev_open = 0; + if (mousedev->opened_by_mixdev) { + mousedev->opened_by_mixdev = false; mousedev_close_device(mousedev); } @@ -969,19 +969,9 @@ static int mousedev_connect(struct input_handler *handler, const struct input_device_id *id) { struct mousedev *mousedev; - int minor; int error; - for (minor = 0; minor < MOUSEDEV_MINORS; minor++) - if (!mousedev_table[minor]) - break; - - if (minor == MOUSEDEV_MINORS) { - pr_err("no more free mousedev devices\n"); - return -ENFILE; - } - - mousedev = mousedev_create(dev, handler, minor); + mousedev = mousedev_create(dev, handler, false); if (IS_ERR(mousedev)) return PTR_ERR(mousedev); @@ -1054,27 +1044,53 @@ static const struct input_device_id mousedev_ids[] = { MODULE_DEVICE_TABLE(input, mousedev_ids); static struct input_handler mousedev_handler = { - .event = mousedev_event, - .connect = mousedev_connect, - .disconnect = mousedev_disconnect, - .fops = &mousedev_fops, - .minor = MOUSEDEV_MINOR_BASE, - .name = "mousedev", - .id_table = mousedev_ids, + .event = mousedev_event, + .connect = mousedev_connect, + .disconnect = mousedev_disconnect, + .legacy_minors = true, + .minor = MOUSEDEV_MINOR_BASE, + .name = "mousedev", + .id_table = mousedev_ids, }; #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX +#include <linux/miscdevice.h> + static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &mousedev_fops + .minor = PSMOUSE_MINOR, + .name = "psaux", + .fops = &mousedev_fops, }; -static int psaux_registered; + +static bool psaux_registered; + +static void __init mousedev_psaux_register(void) +{ + int error; + + error = misc_register(&psaux_mouse); + if (error) + pr_warn("could not register psaux device, error: %d\n", + error); + else + psaux_registered = true; +} + +static void __exit mousedev_psaux_unregister(void) +{ + if (psaux_registered) + misc_deregister(&psaux_mouse); +} +#else +static inline void mousedev_psaux_register(void) { } +static inline void mousedev_psaux_unregister(void) { } #endif static int __init mousedev_init(void) { int error; - mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); + mousedev_mix = mousedev_create(NULL, &mousedev_handler, true); if (IS_ERR(mousedev_mix)) return PTR_ERR(mousedev_mix); @@ -1084,14 +1100,7 @@ static int __init mousedev_init(void) return error; } -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - error = misc_register(&psaux_mouse); - if (error) - pr_warn("could not register psaux device, error: %d\n", - error); - else - psaux_registered = 1; -#endif + mousedev_psaux_register(); pr_info("PS/2 mouse device common for all mice\n"); @@ -1100,10 +1109,7 @@ static int __init mousedev_init(void) static void __exit mousedev_exit(void) { -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (psaux_registered) - misc_deregister(&psaux_mouse); -#endif + mousedev_psaux_unregister(); input_unregister_handler(&mousedev_handler); mousedev_destroy(mousedev_mix); } diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 0d3219f29744..9edf9806cff9 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -172,6 +172,76 @@ static void wacom_close(struct input_dev *dev) } /* + * Calculate the resolution of the X or Y axis, given appropriate HID data. + * This function is little more than hidinput_calc_abs_res stripped down. + */ +static int wacom_calc_hid_res(int logical_extents, int physical_extents, + unsigned char unit, unsigned char exponent) +{ + int prev, unit_exponent; + + /* Check if the extents are sane */ + if (logical_extents <= 0 || physical_extents <= 0) + return 0; + + /* Get signed value of nybble-sized twos-compliment exponent */ + unit_exponent = exponent; + if (unit_exponent > 7) + unit_exponent -= 16; + + /* Convert physical_extents to millimeters */ + if (unit == 0x11) { /* If centimeters */ + unit_exponent += 1; + } else if (unit == 0x13) { /* If inches */ + prev = physical_extents; + physical_extents *= 254; + if (physical_extents < prev) + return 0; + unit_exponent -= 1; + } else { + return 0; + } + + /* Apply negative unit exponent */ + for (; unit_exponent < 0; unit_exponent++) { + prev = logical_extents; + logical_extents *= 10; + if (logical_extents < prev) + return 0; + } + /* Apply positive unit exponent */ + for (; unit_exponent > 0; unit_exponent--) { + prev = physical_extents; + physical_extents *= 10; + if (physical_extents < prev) + return 0; + } + + /* Calculate resolution */ + return logical_extents / physical_extents; +} + +/* + * The physical dimension specified by the HID descriptor is likely not in + * the "100th of a mm" units expected by wacom_calculate_touch_res. This + * function adjusts the value of [xy]_phy based on the unit and exponent + * provided by the HID descriptor. If an error occurs durring conversion + * (e.g. from the unit being left unspecified) [xy]_phy is not modified. + */ +static void wacom_fix_phy_from_hid(struct wacom_features *features) +{ + int xres = wacom_calc_hid_res(features->x_max, features->x_phy, + features->unit, features->unitExpo); + int yres = wacom_calc_hid_res(features->y_max, features->y_phy, + features->unit, features->unitExpo); + + if (xres > 0 && yres > 0) { + features->x_phy = (100 * features->x_max) / xres; + features->y_phy = (100 * features->y_max) / yres; + } +} + +/* * Static values for max X/Y and resolution of Pen interface is stored in * features. This mean physical size of active area can be computed. * This is useful to do when Pen and Touch have same active area of tablet. @@ -432,56 +502,52 @@ static int wacom_parse_hid(struct usb_interface *intf, return result; } -static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) +static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode) { unsigned char *rep_data; - int limit = 0, report_id = 2; - int error = -ENOMEM; + int error = -ENOMEM, limit = 0; - rep_data = kmalloc(4, GFP_KERNEL); + rep_data = kzalloc(length, GFP_KERNEL); if (!rep_data) return error; - /* ask to report Wacom data */ + rep_data[0] = report_id; + rep_data[1] = mode; + + do { + error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, + report_id, rep_data, length, 1); + if (error >= 0) + error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, + report_id, rep_data, length, 1); + } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); + + kfree(rep_data); + + return error < 0 ? error : 0; +} + +/* + * Switch the tablet into its most-capable mode. Wacom tablets are + * typically configured to power-up in a mode which sends mouse-like + * reports to the OS. To get absolute position, pressure data, etc. + * from the tablet, it is necessary to switch the tablet out of this + * mode and into one which sends the full range of tablet data. + */ +static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) +{ if (features->device_type == BTN_TOOL_FINGER) { - /* if it is an MT Tablet PC touch */ if (features->type > TABLETPC) { - do { - rep_data[0] = 3; - rep_data[1] = 4; - rep_data[2] = 0; - rep_data[3] = 0; - report_id = 3; - error = wacom_set_report(intf, - WAC_HID_FEATURE_REPORT, - report_id, - rep_data, 4, 1); - if (error >= 0) - error = wacom_get_report(intf, - WAC_HID_FEATURE_REPORT, - report_id, - rep_data, 4, 1); - } while ((error < 0 || rep_data[1] != 4) && - limit++ < WAC_MSG_RETRIES); + /* MT Tablet PC touch */ + return wacom_set_device_mode(intf, 3, 4, 4); + } + } else if (features->device_type == BTN_TOOL_PEN) { + if (features->type <= BAMBOO_PT && features->type != WIRELESS) { + return wacom_set_device_mode(intf, 2, 2, 2); } - } else if (features->type <= BAMBOO_PT && - features->type != WIRELESS && - features->device_type == BTN_TOOL_PEN) { - do { - rep_data[0] = 2; - rep_data[1] = 2; - error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, - report_id, rep_data, 2, 1); - if (error >= 0) - error = wacom_get_report(intf, - WAC_HID_FEATURE_REPORT, - report_id, rep_data, 2, 1); - } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); } - kfree(rep_data); - - return error < 0 ? error : 0; + return 0; } static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, @@ -531,6 +597,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, error = wacom_parse_hid(intf, hid_desc, features); if (error) goto out; + wacom_fix_phy_from_hid(features); out: return error; diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 08b462b6c0d8..c3468c8dbd89 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -25,6 +25,11 @@ #define WACOM_INTUOS_RES 100 #define WACOM_INTUOS3_RES 200 +/* Scale factor relating reported contact size to logical contact area. + * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo + */ +#define WACOM_CONTACT_AREA_SCALE 2607 + static int wacom_penpartner_irq(struct wacom_wac *wacom) { unsigned char *data = wacom->data; @@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { - if (features->type >= INTUOS5S && features->type <= INTUOS5L) + if (features->quirks == WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = true; /* serial number of the tool */ @@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { - if (features->type >= INTUOS5S && features->type <= INTUOS5L) + if (features->quirks == WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; /* @@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) if (touch) { int x = (data[2] << 4) | (data[4] >> 4); int y = (data[3] << 4) | (data[4] & 0x0f); - int w = data[6]; + int a = data[5]; + + // "a" is a scaled-down area which we assume is roughly + // circular and which can be described as: a=(pi*r^2)/C. + int x_res = input_abs_get_res(input, ABS_X); + int y_res = input_abs_get_res(input, ABS_Y); + int width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE); + int height = width * y_res / x_res; input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); - input_report_abs(input, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, width); + input_report_abs(input, ABS_MT_TOUCH_MINOR, height); } } @@ -1533,7 +1546,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, input_mt_init_slots(input_dev, features->touch_max, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, 255, 0, 0); + 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, + 0, features->y_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, features->x_max, @@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, 255, 0, 0); + 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, + ABS_MT_TOUCH_MINOR, + 0, features->y_max, 0, 0); } input_set_abs_params(input_dev, ABS_MT_POSITION_X, diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index e92615d0b1b0..1df2396af008 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -320,10 +320,8 @@ static bool mxt_object_writable(unsigned int type) static void mxt_dump_message(struct device *dev, struct mxt_message *message) { - dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n", - message->reportid, message->message[0], message->message[1], - message->message[2], message->message[3], message->message[4], - message->message[5], message->message[6]); + dev_dbg(dev, "reportid: %u\tmessage: %*ph\n", + message->reportid, 7, message->message); } static int mxt_check_bootloader(struct i2c_client *client, diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index a1e760150821..61d78fa03b1a 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -595,7 +595,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) j = ipc->num / (sizeof(long) * 8); i = ipc->num % (sizeof(long) * 8); if (j < 8) - protos[j] |= (0x1 << i); + protos[j] |= (1UL << i); ipc = ipc->next; } if ((r = set_arg(argp, protos, 8 * sizeof(long)))) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 8f58f241c10d..7e92793260f0 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -966,6 +966,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) break; } + c->lna = LNA_AUTO; + return 0; } @@ -1054,6 +1056,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0), + + _DTV_CMD(DTV_LNA, 0, 0), }; static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp) @@ -1440,6 +1444,10 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d; break; + case DTV_LNA: + tvp->u.data = c->lna; + break; + default: return -EINVAL; } @@ -1731,10 +1739,6 @@ static int dtv_property_process_set(struct dvb_frontend *fe, case DTV_INTERLEAVING: c->interleaving = tvp->u.data; break; - case DTV_LNA: - if (fe->ops.set_lna) - r = fe->ops.set_lna(fe, tvp->u.data); - break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: @@ -1806,6 +1810,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; break; + case DTV_LNA: + c->lna = tvp->u.data; + if (fe->ops.set_lna) + r = fe->ops.set_lna(fe); + break; + default: return -EINVAL; } @@ -2309,7 +2319,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, fepriv->tune_mode_flags = (unsigned long) parg; err = 0; break; - }; + } return err; } diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 44a445cee74f..97112cd88a17 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -303,7 +303,7 @@ struct dvb_frontend_ops { int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); - int (*set_lna)(struct dvb_frontend *, int); + int (*set_lna)(struct dvb_frontend *); /* These callbacks are for devices that implement their own * tuning algorithms, rather than a simple swzigzag @@ -391,6 +391,8 @@ struct dtv_frontend_properties { u8 atscmh_sccc_code_mode_b; u8 atscmh_sccc_code_mode_c; u8 atscmh_sccc_code_mode_d; + + u32 lna; }; struct dvb_frontend { diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c index cff44a389b40..74fbb5d58bed 100644 --- a/drivers/media/dvb-frontends/a8293.c +++ b/drivers/media/dvb-frontends/a8293.c @@ -90,7 +90,7 @@ static int a8293_set_voltage(struct dvb_frontend *fe, default: ret = -EINVAL; goto err; - }; + } ret = a8293_wr(priv, &priv->reg[0], 1); if (ret) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index e9f04a36577b..a204f2828820 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -241,7 +241,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) KBUILD_MODNAME, gpio); ret = -EINVAL; goto err; - }; + } switch (gpio) { case 0: @@ -253,7 +253,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) default: pos = 4; break; - }; + } ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval); if (ret) @@ -726,7 +726,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__); auto_mode = 1; - }; + } switch (c->modulation) { case QAM_AUTO: diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 8162d939c4b2..464ad878490b 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -408,7 +408,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) { struct af9033_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i, spec_inv; + int ret, i, spec_inv, sampling_freq; u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; @@ -465,18 +465,20 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else if_frequency = 0; - while (if_frequency > (adc_freq / 2)) - if_frequency -= adc_freq; + sampling_freq = if_frequency; - if (if_frequency >= 0) + while (sampling_freq > (adc_freq / 2)) + sampling_freq -= adc_freq; + + if (sampling_freq >= 0) spec_inv *= -1; else - if_frequency *= -1; + sampling_freq *= -1; - freq_cw = af9033_div(state, if_frequency, adc_freq, 23ul); + freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul); if (spec_inv == -1) - freq_cw *= -1; + freq_cw = 0x800000 - freq_cw; /* get adc multiplies */ ret = af9033_rd_reg(state, 0x800045, &tmp); diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 033cd7ad3ca2..1b77909c0c71 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -527,7 +527,7 @@ static int bcm3510_set_frontend(struct dvb_frontend *fe) cmd.ACQUIRE1.IF_FREQ = 0x0; default: return -EINVAL; - }; + } cmd.ACQUIRE0.OFFSET = 0; cmd.ACQUIRE0.NTSCSWEEP = 1; cmd.ACQUIRE0.FA = 1; diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 3180f5b2a6a6..0cd6927e654c 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -218,7 +218,7 @@ static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) } else return -EOPNOTSUPP; /* fixme (low): which is the correct return code? */ - }; + } return 0; } @@ -275,7 +275,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) cx24110_writereg(state,0x07,tmp|0x3); cx24110_writereg(state,0x06,0x78); fclk=90999000UL; - }; + } dprintk("cx24110 debug: fclk %d Hz\n",fclk); /* we need to divide two integers with approx. 27 bits in 32 bit arithmetic giving a 25 bit result */ @@ -362,7 +362,7 @@ static int cx24110_initfe(struct dvb_frontend* fe) for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) { cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); - }; + } return 0; } diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 42648643693e..9b658c1cf39a 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -688,7 +688,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, { struct cxd2820r_priv *priv; int ret; - u8 tmp, gpio[GPIO_COUNT]; + u8 tmp; priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); if (!priv) { @@ -735,6 +735,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, * Use static GPIO configuration if GPIOLIB is undefined. * This is fallback condition. */ + u8 gpio[GPIO_COUNT]; gpio[0] = (*gpio_chip_base >> 0) & 0x07; gpio[1] = (*gpio_chip_base >> 3) & 0x07; gpio[2] = 0; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index f380eb43e9d5..6d9853750d2b 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -991,7 +991,7 @@ static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult) if (nrRetries > DRXD_MAX_RETRIES) { status = -1; break; - }; + } status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0); } while (waitCmd != 0); diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 4c8ac2657c4a..5b639087ce45 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -30,6 +30,7 @@ #include "ds3000.h" static int debug; +static int force_fw_upload; #define dprintk(args...) \ do { \ @@ -392,11 +393,13 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) dprintk("%s()\n", __func__); - if (ds3000_readreg(state, 0xb2) <= 0) + ret = ds3000_readreg(state, 0xb2); + if (ret < 0) return ret; - if (state->skip_fw_load) - return 0; + if (state->skip_fw_load || !force_fw_upload) + return 0; /* Firmware already uploaded, skipping */ + /* Load firmware */ /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, @@ -1306,6 +1309,9 @@ static struct dvb_frontend_ops ds3000_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); +module_param(force_fw_upload, int, 0644); +MODULE_PARM_DESC(force_fw_upload, "Force firmware upload (default:0)"); + MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " "DS3000/TS2020 hardware"); MODULE_AUTHOR("Konstantin Dimitrov"); diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c index dcfc902c8678..d5acc304786b 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c @@ -121,16 +121,13 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; @@ -141,16 +138,13 @@ struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; @@ -161,16 +155,13 @@ struct dvb_frontend *dvb_dummy_fe_qam_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c index 33d33f4d8867..0c642a5bf823 100644 --- a/drivers/media/dvb-frontends/isl6405.c +++ b/drivers/media/dvb-frontends/isl6405.c @@ -77,7 +77,7 @@ static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage break; default: return -EINVAL; - }; + } } isl6405->config |= isl6405->override_or; isl6405->config &= isl6405->override_and; diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index 684c8ec166cb..0cb3f0f74c9c 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -63,7 +63,7 @@ static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage break; default: return -EINVAL; - }; + } isl6421->config |= isl6421->override_or; isl6421->config &= isl6421->override_and; diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c index 316457584fe7..c1c3400b2173 100644 --- a/drivers/media/dvb-frontends/itd1000.c +++ b/drivers/media/dvb-frontends/itd1000.c @@ -231,7 +231,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF; itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln); - itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */; + itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */ itd1000_write_reg(state, PLLNL, plln & 0xff); itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f)); itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff); diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index cc11260e99df..5fd14f840ab0 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1421,8 +1421,8 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, config ? config->i2c_addr : 0); state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL); - if (state == NULL) - goto fail; + if (!state) + return NULL; state->cfg = config; state->i2c_adap = i2c_adap; @@ -1449,10 +1449,6 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, state->frontend.dtv_property_cache.atscmh_parade_id = 1; return &state->frontend; -fail: - lg_warn("unable to detect LG216x hardware\n"); - kfree(state); - return NULL; } EXPORT_SYMBOL(lg2160_attach); diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c index 13437259eeac..f3ba7b5faa2e 100644 --- a/drivers/media/dvb-frontends/lnbp21.c +++ b/drivers/media/dvb-frontends/lnbp21.c @@ -65,7 +65,7 @@ static int lnbp21_set_voltage(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } lnbp21->config |= lnbp21->override_or; lnbp21->config &= lnbp21->override_and; @@ -108,7 +108,7 @@ static int lnbp21_set_tone(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } lnbp21->config |= lnbp21->override_or; lnbp21->config &= lnbp21->override_and; diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c index 84ad0390a4a1..c463da7f6dcc 100644 --- a/drivers/media/dvb-frontends/lnbp22.c +++ b/drivers/media/dvb-frontends/lnbp22.c @@ -73,7 +73,7 @@ static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) break; default: return -EINVAL; - }; + } dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]); return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO; diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c index 8352ce1c9556..6ec16a243741 100644 --- a/drivers/media/dvb-frontends/s5h1432.c +++ b/drivers/media/dvb-frontends/s5h1432.c @@ -351,8 +351,8 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n"); /* allocate memory for the internal state */ state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; /* setup the state */ state->config = config; @@ -367,10 +367,6 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL(s5h1432_attach); diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index cd2288c07147..a271ac3eaec0 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -487,9 +487,9 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, kzalloc(sizeof(struct s921_state), GFP_KERNEL); dprintk("\n"); - if (state == NULL) { + if (!state) { rc("Unable to kzalloc\n"); - goto rcor; + return NULL; } /* setup the state */ @@ -502,11 +502,6 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, state->frontend.demodulator_priv = state; return &state->frontend; - -rcor: - kfree(state); - - return NULL; } EXPORT_SYMBOL(s921_attach); diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index a68a64800df7..73b47cc6a13b 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -343,7 +343,7 @@ static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -472,7 +472,7 @@ static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) break; default: return -EINVAL; - }; + } } static int si21xx_init(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index e37274c8f14e..2aa8ef76eba2 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -188,7 +188,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->hierarchy) { case HIERARCHY_NONE: @@ -207,7 +207,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->code_rate_HP) { case FEC_1_2: @@ -229,7 +229,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index f4096ccb226e..1bb81b5ae6e0 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -229,7 +229,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->hierarchy) { case HIERARCHY_NONE: @@ -248,7 +248,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->code_rate_HP) { case FEC_1_2: @@ -270,7 +270,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index 2e93e65d2cdb..45f9523f968f 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -575,8 +575,8 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, struct stb6100_state *state = NULL; state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -587,10 +587,6 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, printk("%s: Attaching STB6100 \n", __func__); return fe; - -error: - kfree(state); - return NULL; } static int stb6100_release(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c index 057b5f8effc0..92a6075cd82f 100644 --- a/drivers/media/dvb-frontends/stv0299.c +++ b/drivers/media/dvb-frontends/stv0299.c @@ -199,7 +199,7 @@ static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -216,7 +216,7 @@ static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -387,7 +387,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag break; default: return -EINVAL; - }; + } if (state->config->op0_off) reg0x0c &= ~0x10; diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 7f1badaf0d03..262dfa503c2a 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1552,8 +1552,8 @@ static int stv0900_status(struct stv0900_internal *intp, bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) * (tsbitrate1_val << 8 | tsbitrate0_val); bitrate /= 16384; - dprintk("TS bitrate = %d Mbit/sec \n", bitrate); - }; + dprintk("TS bitrate = %d Mbit/sec\n", bitrate); + } return locked; } diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 2c1c759a4f42..63cc12378d9a 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c @@ -228,8 +228,8 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, struct dvb_tuner_info *info; state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); - if (state == NULL) - goto exit; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -246,10 +246,6 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); return fe; - -exit: - kfree(state); - return NULL; } EXPORT_SYMBOL(tda665x_attach); diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c index 15912c96926a..9d08350fe4b0 100644 --- a/drivers/media/dvb-frontends/tda8083.c +++ b/drivers/media/dvb-frontends/tda8083.c @@ -175,7 +175,7 @@ static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) !(tda8083_readreg(state, 0x02) & 0x80)) { msleep(50); - }; + } } static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) @@ -215,7 +215,7 @@ static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_c break; default: return -EINVAL; - }; + } tda8083_wait_diseqc_fifo (state, 100); diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index d8eac3e30a7e..2cee69e34184 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -599,7 +599,7 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write4(client, 0x114, 0x01bf0c9e); cx25840_write4(client, 0x110, 0x000a030c); break; - }; + } /* ADC2 input select */ cx25840_write(client, 0x102, 0x10); diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h index 86c815be348c..90a6c520f115 100644 --- a/drivers/media/i2c/m5mols/m5mols.h +++ b/drivers/media/i2c/m5mols/m5mols.h @@ -16,9 +16,17 @@ #ifndef M5MOLS_H #define M5MOLS_H +#include <linux/sizes.h> #include <media/v4l2-subdev.h> #include "m5mols_reg.h" + +/* An amount of data transmitted in addition to the value + * determined by CAPP_JPEG_SIZE_MAX register. + */ +#define M5MOLS_JPEG_TAGS_SIZE 0x20000 +#define M5MOLS_MAIN_JPEG_SIZE_MAX (5 * SZ_1M) + extern int m5mols_debug; enum m5mols_restype { @@ -67,12 +75,14 @@ struct m5mols_exif { /** * struct m5mols_capture - Structure for the capture capability * @exif: EXIF information + * @buf_size: internal JPEG frame buffer size, in bytes * @main: size in bytes of the main image * @thumb: size in bytes of the thumb image, if it was accompanied * @total: total size in bytes of the produced image */ struct m5mols_capture { struct m5mols_exif exif; + unsigned int buf_size; u32 main; u32 thumb; u32 total; diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c index cb243bd278ce..ab34ccedf31e 100644 --- a/drivers/media/i2c/m5mols/m5mols_capture.c +++ b/drivers/media/i2c/m5mols/m5mols_capture.c @@ -105,6 +105,7 @@ static int m5mols_capture_info(struct m5mols_info *info) int m5mols_start_capture(struct m5mols_info *info) { + unsigned int framesize = info->cap.buf_size - M5MOLS_JPEG_TAGS_SIZE; struct v4l2_subdev *sd = &info->sd; int ret; @@ -121,6 +122,8 @@ int m5mols_start_capture(struct m5mols_info *info) if (!ret) ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution); if (!ret) + ret = m5mols_write(sd, CAPP_JPEG_SIZE_MAX, framesize); + if (!ret) ret = m5mols_set_mode(info, REG_CAPTURE); if (!ret) /* Wait until a frame is captured to ISP internal memory */ diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 2f490ef26c38..8131d651de9e 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -599,6 +599,51 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } +static int m5mols_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct m5mols_info *info = to_m5mols(sd); + + if (pad != 0 || fd == NULL) + return -EINVAL; + + mutex_lock(&info->lock); + /* + * .get_frame_desc is only used for compressed formats, + * thus we always return the capture frame parameters here. + */ + fd->entry[0].length = info->cap.buf_size; + fd->entry[0].pixelcode = info->ffmt[M5MOLS_RESTYPE_CAPTURE].code; + mutex_unlock(&info->lock); + + fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->num_entries = 1; + + return 0; +} + +static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct m5mols_info *info = to_m5mols(sd); + struct v4l2_mbus_framefmt *mf = &info->ffmt[M5MOLS_RESTYPE_CAPTURE]; + + if (pad != 0 || fd == NULL) + return -EINVAL; + + fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->num_entries = 1; + fd->entry[0].length = clamp_t(u32, fd->entry[0].length, + mf->width * mf->height, + M5MOLS_MAIN_JPEG_SIZE_MAX); + mutex_lock(&info->lock); + info->cap.buf_size = fd->entry[0].length; + mutex_unlock(&info->lock); + + return 0; +} + + static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code) @@ -615,6 +660,8 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = { .enum_mbus_code = m5mols_enum_mbus_code, .get_fmt = m5mols_get_fmt, .set_fmt = m5mols_set_fmt, + .get_frame_desc = m5mols_get_frame_desc, + .set_frame_desc = m5mols_set_frame_desc, }; /** diff --git a/drivers/media/i2c/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h index 14d4be72aeff..58d8027508df 100644 --- a/drivers/media/i2c/m5mols/m5mols_reg.h +++ b/drivers/media/i2c/m5mols/m5mols_reg.h @@ -310,6 +310,7 @@ #define REG_JPEG 0x10 #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) +#define CAPP_JPEG_SIZE_MAX I2C_REG(CAT_CAPT_PARM, 0x0f, 4) #define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1) #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 2c0f4077c491..e32833262d32 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -574,7 +574,6 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) #define V4L2_CID_BLC_AUTO (V4L2_CID_USER_BASE | 0x1002) #define V4L2_CID_BLC_TARGET_LEVEL (V4L2_CID_USER_BASE | 0x1003) #define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004) @@ -740,18 +739,6 @@ static const char * const mt9p031_test_pattern_menu[] = { static const struct v4l2_ctrl_config mt9p031_ctrls[] = { { .ops = &mt9p031_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Test Pattern", - .min = 0, - .max = ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, - .step = 0, - .def = 0, - .flags = 0, - .menu_skip_mask = 0, - .qmenu = mt9p031_test_pattern_menu, - }, { - .ops = &mt9p031_ctrl_ops, .id = V4L2_CID_BLC_AUTO, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "BLC, Auto", @@ -950,7 +937,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->model = did->driver_data; mt9p031->reset = -1; - v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5); + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN, @@ -966,6 +953,10 @@ static int mt9p031_probe(struct i2c_client *client, v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_PIXEL_RATE, pdata->target_freq, pdata->target_freq, 1, pdata->target_freq); + v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0, + 0, mt9p031_test_pattern_menu); for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i) v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL); diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 6d343adf891d..2e189d8b71bb 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -371,7 +371,7 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) #define V4L2_CID_BLACK_LEVEL_AUTO (V4L2_CID_USER_BASE | 0x1002) #define V4L2_CID_BLACK_LEVEL_OFFSET (V4L2_CID_USER_BASE | 0x1003) #define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004) @@ -487,12 +487,11 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl) ctrl->val >> 16); case V4L2_CID_TEST_PATTERN: - ret = mt9t001_set_output_control(mt9t001, + return mt9t001_set_output_control(mt9t001, ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA, ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0); - if (ret < 0) - return ret; + case V4L2_CID_TEST_PATTERN_COLOR: return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2); case V4L2_CID_BLACK_LEVEL_AUTO: @@ -533,12 +532,17 @@ static struct v4l2_ctrl_ops mt9t001_ctrl_ops = { .s_ctrl = mt9t001_s_ctrl, }; +static const char * const mt9t001_test_pattern_menu[] = { + "Disabled", + "Enabled", +}; + static const struct v4l2_ctrl_config mt9t001_ctrls[] = { { .ops = &mt9t001_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, + .id = V4L2_CID_TEST_PATTERN_COLOR, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", + .name = "Test Pattern Color", .min = 0, .max = 1023, .step = 1, @@ -741,7 +745,7 @@ static int mt9t001_probe(struct i2c_client *client, return -ENOMEM; v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) + - ARRAY_SIZE(mt9t001_gains) + 3); + ARRAY_SIZE(mt9t001_gains) + 4); v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN, @@ -752,6 +756,10 @@ static int mt9t001_probe(struct i2c_client *client, v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk, 1, pdata->ext_clk); + v4l2_ctrl_new_std_menu_items(&mt9t001->ctrls, &mt9t001_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9t001_test_pattern_menu) - 1, 0, + 0, mt9t001_test_pattern_menu); for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i) v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index e2177405dad2..3f356cb28256 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -141,6 +141,10 @@ struct mt9v032 { u16 chip_control; u16 aec_agc; u16 hblank; + struct { + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *test_pattern_color; + }; }; static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) @@ -500,7 +504,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) { @@ -545,7 +549,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_TEST_PATTERN: - switch (ctrl->val) { + switch (mt9v032->test_pattern->val) { case 0: data = 0; break; @@ -562,13 +566,13 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) | MT9V032_TEST_PATTERN_ENABLE; break; default: - data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT) + data = (mt9v032->test_pattern_color->val << + MT9V032_TEST_PATTERN_DATA_SHIFT) | MT9V032_TEST_PATTERN_USE_DATA | MT9V032_TEST_PATTERN_ENABLE | MT9V032_TEST_PATTERN_FLIP; break; } - return mt9v032_write(client, MT9V032_TEST_PATTERN, data); } @@ -579,18 +583,24 @@ static struct v4l2_ctrl_ops mt9v032_ctrl_ops = { .s_ctrl = mt9v032_s_ctrl, }; -static const struct v4l2_ctrl_config mt9v032_ctrls[] = { - { - .ops = &mt9v032_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", - .min = 0, - .max = 1023, - .step = 1, - .def = 0, - .flags = 0, - } +static const char * const mt9v032_test_pattern_menu[] = { + "Disabled", + "Gray Vertical Shade", + "Gray Horizontal Shade", + "Gray Diagonal Shade", + "Plain", +}; + +static const struct v4l2_ctrl_config mt9v032_test_pattern_color = { + .ops = &mt9v032_ctrl_ops, + .id = V4L2_CID_TEST_PATTERN_COLOR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Test Pattern Color", + .min = 0, + .max = 1023, + .step = 1, + .def = 0, + .flags = 0, }; /* ----------------------------------------------------------------------------- @@ -741,7 +751,7 @@ static int mt9v032_probe(struct i2c_client *client, mutex_init(&mt9v032->power_lock); mt9v032->pdata = pdata; - v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 8); + v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); @@ -763,6 +773,14 @@ static int mt9v032_probe(struct i2c_client *client, V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN, MT9V032_VERTICAL_BLANKING_MAX, 1, MT9V032_VERTICAL_BLANKING_DEF); + mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, + &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9v032_test_pattern_menu) - 1, 0, 0, + mt9v032_test_pattern_menu); + mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls, + &mt9v032_test_pattern_color, NULL); + + v4l2_ctrl_cluster(2, &mt9v032->test_pattern); mt9v032->pixel_rate = v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, @@ -784,8 +802,6 @@ static int mt9v032_probe(struct i2c_client *client, v4l2_ctrl_cluster(2, &mt9v032->link_freq); } - for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i) - v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL); mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 78ac5744cb5d..d2d298b6354e 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -684,6 +684,11 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); u8 val; + int ret; + + ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); + if (ret < 0) + return ret; switch (ctrl->id) { case V4L2_CID_VFLIP: diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index e5c0eedebc58..c31cc04fffd2 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -28,6 +28,18 @@ #include <media/v4l2-subdev.h> #include <media/v4l2-chip-ident.h> +#define THS7303_CHANNEL_1 1 +#define THS7303_CHANNEL_2 2 +#define THS7303_CHANNEL_3 3 + +enum ths7303_filter_mode { + THS7303_FILTER_MODE_480I_576I, + THS7303_FILTER_MODE_480P_576P, + THS7303_FILTER_MODE_720P_1080I, + THS7303_FILTER_MODE_1080P, + THS7303_FILTER_MODE_DISABLE +}; + MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); MODULE_AUTHOR("Chaithrika U S"); MODULE_LICENSE("GPL"); @@ -37,35 +49,96 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-1"); /* following function is used to set ths7303 */ -static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std) +int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode) { + u8 input_bias_chroma = 3; + u8 input_bias_luma = 3; + int disable = 0; int err = 0; - u8 val; - struct i2c_client *client; + u8 val = 0; + u8 temp; - client = v4l2_get_subdevdata(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { - val = 0x02; - v4l2_dbg(1, debug, sd, "setting value for SDTV format\n"); - } else { - val = 0x00; - v4l2_dbg(1, debug, sd, "disabling all channels\n"); + if (!client) + return -EINVAL; + + switch (mode) { + case THS7303_FILTER_MODE_1080P: + val = (3 << 6); + val |= (3 << 3); + break; + case THS7303_FILTER_MODE_720P_1080I: + val = (2 << 6); + val |= (2 << 3); + break; + case THS7303_FILTER_MODE_480P_576P: + val = (1 << 6); + val |= (1 << 3); + break; + case THS7303_FILTER_MODE_480I_576I: + break; + case THS7303_FILTER_MODE_DISABLE: + pr_info("mode disabled\n"); + /* disable all channels */ + disable = 1; + default: + /* disable all channels */ + disable = 1; } + /* Setup channel 2 - Luma - Green */ + temp = val; + if (!disable) + val |= input_bias_luma; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_2, val); + if (err) + goto out; - err |= i2c_smbus_write_byte_data(client, 0x01, val); - err |= i2c_smbus_write_byte_data(client, 0x02, val); - err |= i2c_smbus_write_byte_data(client, 0x03, val); + /* setup two chroma channels */ + if (!disable) + temp |= input_bias_chroma; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_1, temp); if (err) - v4l2_err(sd, "write failed\n"); + goto out; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_3, temp); + if (err) + goto out; + return err; +out: + pr_info("write byte data failed\n"); return err; } static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { - return ths7303_setvalue(sd, norm); + if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) + return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); + else + return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); +} + +/* for setting filter for HD output */ +static int ths7303_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) +{ + u32 height = dv_timings->bt.height; + int interlaced = dv_timings->bt.interlaced; + int res = 0; + + if (height == 1080 && !interlaced) + res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P); + else if ((height == 720 && !interlaced) || + (height == 1080 && interlaced)) + res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I); + else if ((height == 480 || height == 576) && !interlaced) + res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P); + else + /* disable all channels */ + res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); + + return res; } static int ths7303_g_chip_ident(struct v4l2_subdev *sd, @@ -78,6 +151,7 @@ static int ths7303_g_chip_ident(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ths7303_video_ops = { .s_std_output = ths7303_s_std_output, + .s_dv_timings = ths7303_s_dv_timings, }; static const struct v4l2_subdev_core_ops ths7303_core_ops = { @@ -107,7 +181,7 @@ static int ths7303_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &ths7303_ops); - return ths7303_setvalue(sd, std_id); + return ths7303_s_std_output(sd, std_id); } static int ths7303_remove(struct i2c_client *client) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 1f3943bb87d5..d5e10215a28f 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -519,6 +519,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) *std_id = V4L2_STD_UNKNOWN; + /* To query the standard the TVP514x must power on the ADCs. */ + if (!decoder->streaming) { + tvp514x_s_stream(sd, 1); + msleep(LOCK_RETRY_DELAY); + } + /* query the current standard */ current_std = tvp514x_query_current_std(sd); if (current_std == STD_INVALID) @@ -625,25 +631,12 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, int err; enum tvp514x_input input_sel; enum tvp514x_output output_sel; - u8 sync_lock_status, lock_mask; - int try_count = LOCK_RETRY_COUNT; if ((input >= INPUT_INVALID) || (output >= OUTPUT_INVALID)) /* Index out of bound */ return -EINVAL; - /* - * For the sequence streamon -> streamoff and again s_input - * it fails to lock the signal, since streamoff puts TVP514x - * into power off state which leads to failure in sub-sequent s_input. - * - * So power up the TVP514x device here, since it is important to lock - * the signal at this stage. - */ - if (!decoder->streaming) - tvp514x_s_stream(sd, 1); - input_sel = input; output_sel = output; @@ -660,64 +653,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel; decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel; - - /* Clear status */ - msleep(LOCK_RETRY_DELAY); - err = - tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01); - if (err) - return err; - - switch (input_sel) { - case INPUT_CVBS_VI1A: - case INPUT_CVBS_VI1B: - case INPUT_CVBS_VI1C: - case INPUT_CVBS_VI2A: - case INPUT_CVBS_VI2B: - case INPUT_CVBS_VI2C: - case INPUT_CVBS_VI3A: - case INPUT_CVBS_VI3B: - case INPUT_CVBS_VI3C: - case INPUT_CVBS_VI4A: - lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | - STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - - case INPUT_SVIDEO_VI2A_VI1A: - case INPUT_SVIDEO_VI2B_VI1B: - case INPUT_SVIDEO_VI2C_VI1C: - case INPUT_SVIDEO_VI2A_VI3A: - case INPUT_SVIDEO_VI2B_VI3B: - case INPUT_SVIDEO_VI2C_VI3C: - case INPUT_SVIDEO_VI4A_VI1A: - case INPUT_SVIDEO_VI4A_VI1B: - case INPUT_SVIDEO_VI4A_VI1C: - case INPUT_SVIDEO_VI4A_VI3A: - case INPUT_SVIDEO_VI4A_VI3B: - case INPUT_SVIDEO_VI4A_VI3C: - lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - /* Need to add other interfaces*/ - default: - return -EINVAL; - } - - while (try_count-- > 0) { - /* Allow decoder to sync up with new input */ - msleep(LOCK_RETRY_DELAY); - - sync_lock_status = tvp514x_read_reg(sd, - REG_STATUS1); - if (lock_mask == (sync_lock_status & lock_mask)) - /* Input detected */ - break; - } - - if (try_count < 0) - return -EINVAL; - decoder->input = input; decoder->output = output; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index b68918c97f66..56c6c77793d7 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -668,6 +668,12 @@ static const struct v4l2_queryctrl bttv_ctls[] = { .default_value = 32768, .type = V4L2_CTRL_TYPE_INTEGER, },{ + .id = V4L2_CID_COLOR_KILLER, + .name = "Color killer", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { .id = V4L2_CID_HUE, .name = "Hue", .minimum = 0, @@ -1474,6 +1480,9 @@ static int bttv_g_ctrl(struct file *file, void *priv, case V4L2_CID_SATURATION: c->value = btv->saturation; break; + case V4L2_CID_COLOR_KILLER: + c->value = btv->opt_color_killer; + break; case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_VOLUME: @@ -1526,7 +1535,6 @@ static int bttv_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { int err; - int val; struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1547,6 +1555,16 @@ static int bttv_s_ctrl(struct file *file, void *f, case V4L2_CID_SATURATION: bt848_sat(btv, c->value); break; + case V4L2_CID_COLOR_KILLER: + btv->opt_color_killer = c->value; + if (btv->opt_color_killer) { + btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP); + btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP); + } else { + btand(~BT848_SCLOOP_CKILL, BT848_E_SCLOOP); + btand(~BT848_SCLOOP_CKILL, BT848_O_SCLOOP); + } + break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->value); /* fall through */ @@ -1564,9 +1582,13 @@ static int bttv_s_ctrl(struct file *file, void *f, case V4L2_CID_PRIVATE_CHROMA_AGC: btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); + if (btv->opt_chroma_agc) { + btor(BT848_SCLOOP_CAGC, BT848_E_SCLOOP); + btor(BT848_SCLOOP_CAGC, BT848_O_SCLOOP); + } else { + btand(~BT848_SCLOOP_CAGC, BT848_E_SCLOOP); + btand(~BT848_SCLOOP_CAGC, BT848_O_SCLOOP); + } break; case V4L2_CID_PRIVATE_COMBFILTER: btv->opt_combfilter = c->value; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 70fd4f23f605..9ec0adba236c 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -429,6 +429,7 @@ struct bttv { int opt_lumafilter; int opt_automute; int opt_chroma_agc; + int opt_color_killer; int opt_adc_crush; int opt_vcr_hack; int opt_whitecrush_upper; diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index ee3884fbc9ce..7d96fab7d246 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -646,7 +646,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); default: result = -EOPNOTSUPP; - }; + } free_mem_and_exit: kfree (p_ca_message); kfree (p_ca_slot_info); diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index aee7f0dacff1..495781ee4711 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -416,7 +416,7 @@ static void netup_read_ci_status(struct work_struct *work) DVB_CA_EN50221_POLL_CAM_READY : 0); ci_dbg_print("%s: setting CI[1] status = 0x%x\n", __func__, inter->state[1]->status); - }; + } if (inter->state[0] != NULL) { inter->state[0]->status = @@ -425,7 +425,7 @@ static void netup_read_ci_status(struct work_struct *work) DVB_CA_EN50221_POLL_CAM_READY : 0); ci_dbg_print("%s: setting CI[0] status = 0x%x\n", __func__, inter->state[0]->status); - }; + } } /* CI irq handler */ diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index c9f15d6dec40..6617774a326a 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -193,7 +193,7 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, 0, &store, 1); if (ret != 0) return ret; - }; + } state->current_ci_flag = flag; mutex_lock(&dev->gpio_lock); diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 39a4a4b9ed7e..5acdf954ff6b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -542,11 +542,13 @@ struct cx23885_board cx23885_boards[] = { { .type = CX23885_VMUX_COMPOSITE1, .vmux = CX25840_COMPOSITE8, + .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_SVIDEO, .vmux = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4, + .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_COMPONENT, @@ -554,6 +556,7 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN1_CH1 | CX25840_VIN6_CH2 | CX25840_VIN7_CH3, + .amux = CX25840_AUDIO7, }, }, }, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 8c4a9a5f9a50..1a21926ca412 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -508,7 +508,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || + (dev->board == CX23885_BOARD_MYGICA_X8507)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c index c8c94fbf5d8d..d33fc1a23030 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c @@ -761,7 +761,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, } /* Default if filename is empty string */ - if (strcmp(dev->input_filename_ch2, "") == 0) { + if (strcmp(dev->_filename_ch2, "") == 0) { if (dev->_isNTSC_ch2) { dev->_filename_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? "/root/vid411.yuv" : diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 52c13e0b6492..6759fff8eb64 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -808,7 +808,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, } /* Default if filename is empty string */ - if (strcmp(dev->input_filename, "") == 0) { + if (strcmp(dev->_filename, "") == 0) { if (dev->_isNTSC) { dev->_filename = (dev->_pixel_format == PIXEL_FRMT_411) ? diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index def363fb71c0..62184eb919e5 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -721,7 +721,7 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -739,7 +739,7 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); @@ -755,7 +755,7 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index d803bba09525..666f83b2f3c0 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -896,7 +896,7 @@ static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO; } diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index c04fb618e10b..d154bc197356 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -450,7 +450,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) cx88_core_irq(core,status); if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); - }; + } if (MAX_IRQ_LOOP == loop) { dprintk( 0, "clearing mask\n" ); printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 770ec05b5e9b..424fd97495dc 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -373,7 +373,7 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) set_audio_registers(core, nicam_bgdki_common); set_audio_registers(core, nicam_default); break; - }; + } mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; set_audio_finish(core, mode); @@ -639,7 +639,7 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode) dprintk("%s Warning: wrong value\n", __func__); return; break; - }; + } mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; set_audio_finish(core, mode); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index a146d50d7795..05171457bf28 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1535,7 +1535,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) cx88_core_irq(core,status); if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); - }; + } if (10 == loop) { printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", core->name); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 22f8758d047f..4a77124ee70e 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1204,7 +1204,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str break; default: /* nothing */; - }; + } switch (c->id) { case V4L2_CID_BRIGHTNESS: dev->ctl_bright = c->value; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f588d6296c76..181c7686e412 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -165,12 +165,12 @@ config VIDEO_SAMSUNG_S5P_JPEG This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec config VIDEO_SAMSUNG_S5P_MFC - tristate "Samsung S5P MFC 5.1 Video Codec" + tristate "Samsung S5P MFC Video Codec" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P select VIDEOBUF2_DMA_CONTIG default n help - MFC 5.1 driver for V4L2. + MFC 5.1 and 6.x driver for V4L2 config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index c4a82a1a8a97..69d7a58c92c3 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -174,26 +174,6 @@ static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, return 0; } -static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, - unsigned int dv_preset) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if ((var.timings_type & VPBE_ENC_DV_PRESET) && - (var.timings.dv_preset == dv_preset)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - /* Get std by std id */ static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) @@ -206,7 +186,7 @@ static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { var = cfg->outputs[curr_output].modes[i]; if ((var.timings_type & VPBE_ENC_STD) && - (var.timings.std_id & std_id)) { + (var.std_id & std_id)) { vpbe_dev->current_timings = var; return 0; } @@ -344,38 +324,42 @@ static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) } /** - * vpbe_s_dv_preset - Set the given preset timings in the encoder + * vpbe_s_dv_timings - Set the given preset timings in the encoder * - * Sets the preset if supported by the current encoder. Return the status. + * Sets the timings if supported by the current encoder. Return the status. * 0 - success & -EINVAL on error */ -static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset) +static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &cfg->outputs[out_index]; int sd_index = vpbe_dev->current_sd_index; - int ret; + int ret, i; if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_PRESETS)) + V4L2_OUT_CAP_DV_TIMINGS)) return -EINVAL; - ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); - - if (ret) - return ret; - + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS && + !memcmp(&output->modes[i].dv_timings, + dv_timings, sizeof(*dv_timings))) + break; + } + if (i >= output->num_modes) + return -EINVAL; + vpbe_dev->current_timings = output->modes[i]; mutex_lock(&vpbe_dev->lock); - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_dv_preset, dv_preset); + s_dv_timings, dv_timings); if (!ret && (vpbe_dev->amp != NULL)) { /* Call amplifier subdevice */ ret = v4l2_subdev_call(vpbe_dev->amp, video, - s_dv_preset, dv_preset); + s_dv_timings, dv_timings); } /* set the lcd controller output for the given mode */ if (!ret) { @@ -392,17 +376,17 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, } /** - * vpbe_g_dv_preset - Get the preset in the current encoder + * vpbe_g_dv_timings - Get the timings in the current encoder * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ -static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset) +static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings) { if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_PRESET) { - dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + VPBE_ENC_CUSTOM_TIMINGS) { + *dv_timings = vpbe_dev->current_timings.dv_timings; return 0; } @@ -410,13 +394,13 @@ static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, } /** - * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ -static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, - struct v4l2_dv_enum_preset *preset_info) +static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_enum_dv_timings *timings) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; @@ -424,12 +408,12 @@ static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, int j = 0; int i; - if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)) return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { - if (j == preset_info->index) + if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS) { + if (j == timings->index) break; j++; } @@ -437,9 +421,8 @@ static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, if (i == output->num_modes) return -EINVAL; - - return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, - preset_info); + timings->timings = output->modes[i].dv_timings; + return 0; } /** @@ -489,10 +472,10 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) */ static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) { - struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings; - if (cur_timings.timings_type & VPBE_ENC_STD) { - *std_id = cur_timings.timings.std_id; + if (cur_timings->timings_type & VPBE_ENC_STD) { + *std_id = cur_timings->std_id; return 0; } @@ -511,7 +494,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, { struct vpbe_enc_mode_info *preset_mode = NULL; struct vpbe_config *cfg = vpbe_dev->cfg; - struct v4l2_dv_preset dv_preset; + struct v4l2_dv_timings dv_timings; struct osd_state *osd_device; int out_index = vpbe_dev->current_out_index; int ret = 0; @@ -530,11 +513,12 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, */ if (preset_mode->timings_type & VPBE_ENC_STD) return vpbe_s_std(vpbe_dev, - &preset_mode->timings.std_id); - if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { - dv_preset.preset = - preset_mode->timings.dv_preset; - return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + &preset_mode->std_id); + if (preset_mode->timings_type & + VPBE_ENC_CUSTOM_TIMINGS) { + dv_timings = + preset_mode->dv_timings; + return vpbe_s_dv_timings(vpbe_dev, &dv_timings); } } } @@ -626,11 +610,11 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); if (IS_ERR(vpbe_dev->dac_clk)) { ret = PTR_ERR(vpbe_dev->dac_clk); - goto vpbe_unlock; + goto fail_mutex_unlock; } if (clk_enable(vpbe_dev->dac_clk)) { ret = -ENODEV; - goto vpbe_unlock; + goto fail_mutex_unlock; } } @@ -642,7 +626,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) if (ret) { v4l2_err(dev->driver, "Unable to register v4l2 device.\n"); - goto vpbe_fail_clock; + goto fail_clk_put; } v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); @@ -658,7 +642,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "vpbe unable to init venc sub device\n"); ret = -ENODEV; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } /* initialize osd device */ osd_device = vpbe_dev->osd_device; @@ -669,7 +653,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "unable to initialize the OSD device"); err = -ENOMEM; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } } @@ -685,7 +669,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "unable to allocate memory for encoders sub devices"); ret = -ENOMEM; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); @@ -711,7 +695,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) " failed to register", enc_info->module_name); ret = -ENODEV; - goto vpbe_fail_sd_register; + goto fail_kfree_encoders; } } else v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" @@ -730,7 +714,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) "amplifier %s failed to register", amp_info->module_name); ret = -ENODEV; - goto vpbe_fail_amp_register; + goto fail_kfree_encoders; } v4l2_info(&vpbe_dev->v4l2_dev, "v4l2 sub device %s registered\n", @@ -770,16 +754,14 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) /* TBD handling of bootargs for default output and mode */ return 0; -vpbe_fail_amp_register: - kfree(vpbe_dev->amp); -vpbe_fail_sd_register: +fail_kfree_encoders: kfree(vpbe_dev->encoders); -vpbe_fail_v4l2_device: +fail_dev_unregister: v4l2_device_unregister(&vpbe_dev->v4l2_dev); -vpbe_fail_clock: +fail_clk_put: if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) clk_put(vpbe_dev->dac_clk); -vpbe_unlock: +fail_mutex_unlock: mutex_unlock(&vpbe_dev->lock); return ret; } @@ -810,9 +792,9 @@ static struct vpbe_device_ops vpbe_dev_ops = { .enum_outputs = vpbe_enum_outputs, .set_output = vpbe_set_output, .get_output = vpbe_get_output, - .s_dv_preset = vpbe_s_dv_preset, - .g_dv_preset = vpbe_g_dv_preset, - .enum_dv_presets = vpbe_enum_dv_presets, + .s_dv_timings = vpbe_s_dv_timings, + .g_dv_timings = vpbe_g_dv_timings, + .enum_dv_timings = vpbe_enum_dv_timings, .s_std = vpbe_s_std, .g_std = vpbe_g_std, .initialize = vpbe_initialize, diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 239f37bfa313..161c77650e2f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -393,7 +393,7 @@ vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, int h_scale; int v_scale; - v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + v4l2_std_id standard_id = vpbe_dev->current_timings.std_id; /* * Application initially set the image format. Current display @@ -637,7 +637,7 @@ static int vpbe_display_s_crop(struct file *file, void *priv, struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; struct osd_layer_config *cfg = &layer->layer_info.config; struct osd_state *osd_device = disp_dev->osd_device; - struct v4l2_rect *rect = &crop->c; + struct v4l2_rect rect = crop->c; int ret; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, @@ -648,21 +648,21 @@ static int vpbe_display_s_crop(struct file *file, void *priv, return -EINVAL; } - if (rect->top < 0) - rect->top = 0; - if (rect->left < 0) - rect->left = 0; + if (rect.top < 0) + rect.top = 0; + if (rect.left < 0) + rect.left = 0; - vpbe_disp_check_window_params(disp_dev, rect); + vpbe_disp_check_window_params(disp_dev, &rect); osd_device->ops.get_layer_config(osd_device, layer->layer_info.id, cfg); vpbe_disp_calculate_scale_factor(disp_dev, layer, - rect->width, - rect->height); - vpbe_disp_adj_position(disp_dev, layer, rect->top, - rect->left); + rect.width, + rect.height); + vpbe_disp_adj_position(disp_dev, layer, rect.top, + rect.left); ret = osd_device->ops.set_layer_config(osd_device, layer->layer_info.id, cfg); if (ret < 0) { @@ -943,7 +943,7 @@ static int vpbe_display_g_std(struct file *file, void *priv, /* Get the standard from the current encoder */ if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { - *std_id = vpbe_dev->current_timings.timings.std_id; + *std_id = vpbe_dev->current_timings.std_id; return 0; } @@ -1029,29 +1029,29 @@ static int vpbe_display_g_output(struct file *file, void *priv, } /** - * vpbe_display_enum_dv_presets - Enumerate the dv presets + * vpbe_display_enum_dv_timings - Enumerate the dv timings * - * enum the preset in the current encoder. Return the status. 0 - success + * enum the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_enum_dv_presets(struct file *file, void *priv, - struct v4l2_dv_enum_preset *preset) +vpbe_display_enum_dv_timings(struct file *file, void *priv, + struct v4l2_enum_dv_timings *timings) { struct vpbe_fh *fh = priv; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); /* Enumerate outputs */ - if (NULL == vpbe_dev->ops.enum_dv_presets) + if (NULL == vpbe_dev->ops.enum_dv_timings) return -EINVAL; - ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to enumerate dv presets info\n"); + "Failed to enumerate dv timings info\n"); return -EINVAL; } @@ -1059,21 +1059,21 @@ vpbe_display_enum_dv_presets(struct file *file, void *priv, } /** - * vpbe_display_s_dv_preset - Set the dv presets + * vpbe_display_s_dv_timings - Set the dv timings * - * Set the preset in the current encoder. Return the status. 0 - success + * Set the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_s_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) +vpbe_display_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) { struct vpbe_fh *fh = priv; struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_TIMINGS\n"); /* If streaming is started, return error */ @@ -1083,13 +1083,13 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /* Set the given standard in the encoder */ - if (!vpbe_dev->ops.s_dv_preset) + if (!vpbe_dev->ops.s_dv_timings) return -EINVAL; - ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + ret = vpbe_dev->ops.s_dv_timings(vpbe_dev, timings); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set the dv presets info\n"); + "Failed to set the dv timings info\n"); return -EINVAL; } /* set the current norm to zero to be consistent. If STD is used @@ -1101,26 +1101,25 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /** - * vpbe_display_g_dv_preset - Set the dv presets + * vpbe_display_g_dv_timings - Set the dv timings * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_g_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *dv_preset) +vpbe_display_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *dv_timings) { struct vpbe_fh *fh = priv; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_TIMINGS\n"); /* Get the given standard in the encoder */ if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_PRESET) { - dv_preset->preset = - vpbe_dev->current_timings.timings.dv_preset; + VPBE_ENC_CUSTOM_TIMINGS) { + *dv_timings = vpbe_dev->current_timings.dv_timings; } else { return -EINVAL; } @@ -1572,9 +1571,9 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { .vidioc_enum_output = vpbe_display_enum_output, .vidioc_s_output = vpbe_display_s_output, .vidioc_g_output = vpbe_display_g_output, - .vidioc_s_dv_preset = vpbe_display_s_dv_preset, - .vidioc_g_dv_preset = vpbe_display_g_dv_preset, - .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, + .vidioc_s_dv_timings = vpbe_display_s_dv_timings, + .vidioc_g_dv_timings = vpbe_display_g_dv_timings, + .vidioc_enum_dv_timings = vpbe_display_enum_dv_timings, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpbe_display_g_register, .vidioc_s_register = vpbe_display_s_register, @@ -1639,8 +1638,7 @@ static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev, VPBE_ENC_STD) { vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); vbd->current_norm = - disp_dev->vpbe_dev-> - current_timings.timings.std_id; + disp_dev->vpbe_dev->current_timings.std_id; } else vbd->current_norm = 0; diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index 0302669622d6..aed7369b962a 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -298,7 +298,7 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -345,7 +345,7 @@ static int venc_set_576p50(struct v4l2_subdev *sd) (pdata->venc_type != VPBE_VERSION_2)) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -385,7 +385,7 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -413,7 +413,7 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -446,26 +446,27 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) return -EINVAL; } -static int venc_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *dv_preset) +static int venc_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) { struct venc_state *venc = to_state(sd); + u32 height = dv_timings->bt.height; int ret; - v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n"); - if (dv_preset->preset == V4L2_DV_576P50) + if (height == 576) return venc_set_576p50(sd); - else if (dv_preset->preset == V4L2_DV_480P59_94) + else if (height == 480) return venc_set_480p59_94(sd); - else if ((dv_preset->preset == V4L2_DV_720P60) && + else if ((height == 720) && (venc->pdata->venc_type == VPBE_VERSION_2)) { /* TBD setup internal 720p mode here */ ret = venc_set_720p60_internal(sd); /* for DM365 VPBE, there is DAC inside */ vdaccfg_write(sd, VDAC_CONFIG_HD_V2); return ret; - } else if ((dv_preset->preset == V4L2_DV_1080I30) && + } else if ((height == 1080) && (venc->pdata->venc_type == VPBE_VERSION_2)) { /* TBD setup internal 1080i mode here */ ret = venc_set_1080i30_internal(sd); @@ -518,7 +519,7 @@ static const struct v4l2_subdev_core_ops venc_core_ops = { static const struct v4l2_subdev_video_ops venc_video_ops = { .s_routing = venc_s_routing, .s_std_output = venc_s_std_output, - .s_dv_preset = venc_s_dv_preset, + .s_dv_timings = venc_s_dv_timings, }; static const struct v4l2_subdev_ops venc_ops = { diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 48052cbffc2b..8be492cd8ed4 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1669,6 +1669,7 @@ static int vpfe_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { struct vpfe_device *vpfe_dev = video_drvdata(file); + struct v4l2_rect rect = crop->c; int ret = 0; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); @@ -1684,7 +1685,7 @@ static int vpfe_s_crop(struct file *file, void *priv, if (ret) return ret; - if (crop->c.top < 0 || crop->c.left < 0) { + if (rect.top < 0 || rect.left < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "doesn't support negative values for top & left\n"); ret = -EINVAL; @@ -1692,26 +1693,26 @@ static int vpfe_s_crop(struct file *file, void *priv, } /* adjust the width to 16 pixel boundary */ - crop->c.width = ((crop->c.width + 15) & ~0xf); + rect.width = ((rect.width + 15) & ~0xf); /* make sure parameters are valid */ - if ((crop->c.left + crop->c.width > + if ((rect.left + rect.width > vpfe_dev->std_info.active_pixels) || - (crop->c.top + crop->c.height > + (rect.top + rect.height > vpfe_dev->std_info.active_lines)) { v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); ret = -EINVAL; goto unlock_out; } - ccdc_dev->hw_ops.set_image_window(&crop->c); - vpfe_dev->fmt.fmt.pix.width = crop->c.width; - vpfe_dev->fmt.fmt.pix.height = crop->c.height; + ccdc_dev->hw_ops.set_image_window(&rect); + vpfe_dev->fmt.fmt.pix.width = rect.width; + vpfe_dev->fmt.fmt.pix.height = rect.height; vpfe_dev->fmt.fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); vpfe_dev->fmt.fmt.pix.sizeimage = vpfe_dev->fmt.fmt.pix.bytesperline * vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = crop->c; + vpfe_dev->crop = rect; unlock_out: mutex_unlock(&vpfe_dev->lock); return ret; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0bafecac4923..fcabc023885d 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -311,12 +311,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) } /* configure 1 or 2 channel mode */ - ret = vpif_config_data->setup_input_channel_mode - (vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - return ret; + if (vpif_config_data->setup_input_channel_mode) { + ret = vpif_config_data-> + setup_input_channel_mode(vpif->std_info.ycmux_mode); + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + return ret; + } } /* Call vpif_set_params function to set the parameters and addresses */ @@ -863,13 +864,11 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait) */ static int vpif_open(struct file *filep) { - struct vpif_capture_config *config = vpif_dev->platform_data; struct video_device *vdev = video_devdata(filep); struct common_obj *common; struct video_obj *vid_ch; struct channel_obj *ch; struct vpif_fh *fh; - int i; vpif_dbg(2, debug, "vpif_open\n"); @@ -878,26 +877,6 @@ static int vpif_open(struct file *filep) vid_ch = &ch->video; common = &ch->common[VPIF_VIDEO_INDEX]; - if (NULL == ch->curr_subdev_info) { - /** - * search through the sub device to see a registered - * sub device and make it as current sub device - */ - for (i = 0; i < config->subdev_count; i++) { - if (vpif_obj.sd[i]) { - /* the sub device is registered */ - ch->curr_subdev_info = &config->subdev_info[i]; - /* make first input as the current input */ - vid_ch->input_idx = 0; - break; - } - } - if (i == config->subdev_count) { - vpif_err("No sub device registered\n"); - return -ENOENT; - } - } - /* Allocate memory for the file handle object */ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); if (NULL == fh) { @@ -997,6 +976,7 @@ static int vpif_reqbufs(struct file *file, void *priv, struct common_obj *common; u8 index = 0; struct vb2_queue *q; + int ret; vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -1036,8 +1016,12 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); - vb2_queue_init(q); - + ret = vb2_queue_init(q); + if (ret) { + vpif_err("vpif_capture: vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; /* Increment io usrs member of channel object to 1 */ @@ -1175,10 +1159,9 @@ static int vpif_streamon(struct file *file, void *priv, return ret; /* Enable streamon on the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 1); + ret = v4l2_subdev_call(ch->sd, video, s_stream, 1); - if (ret && (ret != -ENOIOCTLCMD)) { + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "stream on failed in subdev\n"); return ret; } @@ -1238,73 +1221,105 @@ static int vpif_streamoff(struct file *file, void *priv, common->started = 0; - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 0); + ret = v4l2_subdev_call(ch->sd, video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) vpif_dbg(1, debug, "stream off failed in subdev\n"); return vb2_streamoff(&common->buffer_queue, buftype); } /** - * vpif_map_sub_device_to_input() - Maps sub device to input - * @ch - ptr to channel - * @config - ptr to capture configuration + * vpif_input_to_subdev() - Maps input to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr * @input_index - Given input index from application - * @sub_device_index - index into sd table * * lookup the sub device information for a given input index. * we report all the inputs to application. inputs table also * has sub device name for the each input */ -static struct vpif_subdev_info *vpif_map_sub_device_to_input( - struct channel_obj *ch, - struct vpif_capture_config *vpif_cfg, - int input_index, - int *sub_device_index) +static int vpif_input_to_subdev( + struct vpif_capture_config *vpif_cfg, + struct vpif_capture_chan_config *chan_cfg, + int input_index) { - struct vpif_capture_chan_config *chan_cfg; - struct vpif_subdev_info *subdev_info = NULL; - const char *subdev_name = NULL; + struct vpif_subdev_info *subdev_info; + const char *subdev_name; int i; - vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); + vpif_dbg(2, debug, "vpif_input_to_subdev\n"); - chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - - /** - * search through the inputs to find the sub device supporting - * the input - */ - for (i = 0; i < chan_cfg->input_count; i++) { - /* For each sub device, loop through input */ - if (i == input_index) { - subdev_name = chan_cfg->inputs[i].subdev_name; - break; - } - } - - /* if reached maximum. return null */ - if (i == chan_cfg->input_count || (NULL == subdev_name)) - return subdev_info; + subdev_name = chan_cfg->inputs[input_index].subdev_name; + if (subdev_name == NULL) + return -1; /* loop through the sub device list to get the sub device info */ for (i = 0; i < vpif_cfg->subdev_count; i++) { subdev_info = &vpif_cfg->subdev_info[i]; if (!strcmp(subdev_info->name, subdev_name)) - break; + return i; + } + return -1; +} + +/** + * vpif_set_input() - Select an input + * @vpif_cfg - global config ptr + * @ch - channel + * @_index - Given input index from application + * + * Select the given input. + */ +static int vpif_set_input( + struct vpif_capture_config *vpif_cfg, + struct channel_obj *ch, + int index) +{ + struct vpif_capture_chan_config *chan_cfg = + &vpif_cfg->chan_config[ch->channel_id]; + struct vpif_subdev_info *subdev_info = NULL; + struct v4l2_subdev *sd = NULL; + u32 input = 0, output = 0; + int sd_index; + int ret; + + sd_index = vpif_input_to_subdev(vpif_cfg, chan_cfg, index); + if (sd_index >= 0) { + sd = vpif_obj.sd[sd_index]; + subdev_info = &vpif_cfg->subdev_info[sd_index]; } - if (i == vpif_cfg->subdev_count) - return subdev_info; + /* first setup input path from sub device to vpif */ + if (sd && vpif_cfg->setup_input_path) { + ret = vpif_cfg->setup_input_path(ch->channel_id, + subdev_info->name); + if (ret < 0) { + vpif_dbg(1, debug, "couldn't setup input path for the" \ + " sub device %s, for input index %d\n", + subdev_info->name, index); + return ret; + } + } - /* check if the sub device is registered */ - if (NULL == vpif_obj.sd[i]) - return NULL; + if (sd) { + input = chan_cfg->inputs[index].input_route; + output = chan_cfg->inputs[index].output_route; + ret = v4l2_subdev_call(sd, video, s_routing, + input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_dbg(1, debug, "Failed to set input\n"); + return ret; + } + } + ch->input_idx = index; + ch->sd = sd; + /* copy interface parameters to vpif */ + ch->vpifparams.iface = chan_cfg->vpif_if; - *sub_device_index = i; - return subdev_info; + /* update tvnorms from the sub device input info */ + ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; + return 0; } /** @@ -1324,12 +1339,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) vpif_dbg(2, debug, "vpif_querystd\n"); /* Call querystd function of decoder device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - querystd, std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + ret = v4l2_subdev_call(ch->sd, video, querystd, std_id); - return ret; + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + return -ENODATA; + if (ret) { + vpif_dbg(1, debug, "Failed to query standard for sub devices\n"); + return ret; + } + + return 0; } /** @@ -1397,11 +1416,12 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); /* set standard in the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_std, *std_id); - if (ret < 0) + ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - return ret; + return ret; + } + return 0; } /** @@ -1441,10 +1461,8 @@ static int vpif_g_input(struct file *file, void *priv, unsigned int *index) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *index = vid_ch->input_idx; + *index = ch->input_idx; return 0; } @@ -1461,13 +1479,13 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - struct vpif_subdev_info *subdev_info; - int ret = 0, sd_index = 0; - u32 input = 0, output = 0; + int ret; chan_cfg = &config->chan_config[ch->channel_id]; + if (index >= chan_cfg->input_count) + return -EINVAL; + if (common->started) { vpif_err("Streaming in progress\n"); return -EBUSY; @@ -1486,45 +1504,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) return ret; fh->initialized = 1; - subdev_info = vpif_map_sub_device_to_input(ch, config, index, - &sd_index); - if (NULL == subdev_info) { - vpif_dbg(1, debug, - "couldn't lookup sub device for the input index\n"); - return -EINVAL; - } - - /* first setup input path from sub device to vpif */ - if (config->setup_input_path) { - ret = config->setup_input_path(ch->channel_id, - subdev_info->name); - if (ret < 0) { - vpif_dbg(1, debug, "couldn't setup input path for the" - " sub device %s, for input index %d\n", - subdev_info->name, index); - return ret; - } - } - - if (subdev_info->can_route) { - input = subdev_info->input; - output = subdev_info->output; - ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, - input, output, 0); - if (ret < 0) { - vpif_dbg(1, debug, "Failed to set input\n"); - return ret; - } - } - vid_ch->input_idx = index; - ch->curr_subdev_info = subdev_info; - ch->curr_sd_index = sd_index; - /* copy interface parameters to vpif */ - ch->vpifparams.iface = subdev_info->vpif_if; - - /* update tvnorms from the sub device input info */ - ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - return ret; + return vpif_set_input(config, ch, index); } /** @@ -1655,9 +1635,11 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpif_dev)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -1730,9 +1712,12 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, enum_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -EINVAL; + return ret; } /** @@ -1747,9 +1732,12 @@ vpif_query_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, query_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, query_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -ENODATA; + return ret; } /** @@ -1775,13 +1763,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } + ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + ret = 0; if (ret < 0) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; @@ -1906,8 +1890,7 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - g_register, reg); + return v4l2_subdev_call(ch->sd, core, g_register, reg); } /* @@ -1924,8 +1907,7 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_register, reg); + return v4l2_subdev_call(ch->sd, core, s_register, reg); } #endif @@ -2063,7 +2045,8 @@ static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct vpif_capture_config *config; - int i, j, k, m, q, err; + int i, j, k, err; + int res_idx = 0; struct i2c_adapter *i2c_adap; struct channel_obj *ch; struct common_obj *common; @@ -2086,18 +2069,19 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, vpif_channel_isr, IRQF_SHARED, - "VPIF_Capture", - (void *)(&vpif_obj.dev[k]->channel_id))) { + "VPIF_Capture", (void *) + (&vpif_obj.dev[res_idx]->channel_id))) { err = -EBUSY; - i--; + for (j = 0; j < i; j++) + free_irq(j, (void *) + (&vpif_obj.dev[res_idx]->channel_id)); goto vpif_int_err; } } - k++; + res_idx++; } for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { @@ -2111,7 +2095,7 @@ static __init int vpif_probe(struct platform_device *pdev) video_device_release(ch->video_dev); } err = -ENOMEM; - goto vpif_dev_alloc_err; + goto vpif_int_err; } /* Initialize field of video device */ @@ -2142,24 +2126,6 @@ static __init int vpif_probe(struct platform_device *pdev) } } - for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - ch->channel_id = j; - common = &(ch->common[VPIF_VIDEO_INDEX]); - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - ch->video_dev->lock = &common->lock; - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 1 : 0)); - if (err) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - - } - i2c_adap = i2c_get_adapter(1); config = pdev->dev.platform_data; @@ -2169,7 +2135,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto probe_out; + goto vpif_sd_error; } for (i = 0; i < subdev_count; i++) { @@ -2186,19 +2152,32 @@ static __init int vpif_probe(struct platform_device *pdev) } v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", subdevdata->name); - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; } + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + common = &(ch->common[VPIF_VIDEO_INDEX]); + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + ch->video_dev->lock = &common->lock; + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + video_set_drvdata(ch->video_dev, ch); + + /* select input 0 */ + err = vpif_set_input(config, ch, 0); + if (err) + goto probe_out; + + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 1 : 0)); + if (err) + goto probe_out; + } v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n"); return 0; -probe_subdev_out: - /* free sub devices memory */ - kfree(vpif_obj.sd); - - j = VPIF_CAPTURE_MAX_DEVICES; probe_out: for (k = 0; k < j; k++) { /* Get the pointer to the channel object */ @@ -2206,22 +2185,23 @@ probe_out: /* Unregister video device */ video_unregister_device(ch->video_dev); } +probe_subdev_out: + /* free sub devices memory */ + kfree(vpif_obj.sd); -vpif_dev_alloc_err: - k = VPIF_CAPTURE_MAX_DEVICES-1; - res = platform_get_resource(pdev, IORESOURCE_IRQ, k); - i = res->end; - -vpif_int_err: - for (q = k; q >= 0; q--) { - for (m = i; m >= (int)res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); - if (res) - i = res->end; +vpif_sd_error: + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + ch = vpif_obj.dev[i]; + /* Note: does nothing if ch->video_dev == NULL */ + video_device_release(ch->video_dev); } +vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); + for (i = 0; i < res_idx; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + for (j = res->start; j <= res->end; j++) + free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); + } return err; } diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index d24efc17e4c8..3d3c1e5cd5d4 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -54,8 +54,6 @@ struct video_obj { /* Currently selected or default standard */ v4l2_std_id stdid; struct v4l2_dv_timings dv_timings; - /* This is to track the last input that is passed to application */ - u32 input_idx; }; struct vpif_cap_buffer { @@ -119,10 +117,10 @@ struct channel_obj { u8 initialized; /* Identifies channel */ enum vpif_channel_id channel_id; - /* index into sd table */ - int curr_sd_index; - /* ptr to current sub device information */ - struct vpif_subdev_info *curr_subdev_info; + /* Current input */ + u32 input_idx; + /* subdev corresponding to the current input, may be NULL */ + struct v4l2_subdev *sd; /* vpif configuration params */ struct vpif_params vpifparams; /* common object array */ @@ -159,10 +157,6 @@ struct vpif_config_params { u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS]; u8 max_device_type; }; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; -}; + #endif /* End of __KERNEL__ */ #endif /* VPIF_CAPTURE_H */ diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a5b88689abad..b716fbd4241f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -280,12 +280,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) } /* clock settings */ - ret = - vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, - ch->vpifparams.std_info.hd_sd); - if (ret < 0) { - vpif_err("can't set clock\n"); - return ret; + if (vpif_config_data->set_clock) { + ret = vpif_config_data->set_clock(ch->vpifparams.std_info. + ycmux_mode, ch->vpifparams.std_info.hd_sd); + if (ret < 0) { + vpif_err("can't set clock\n"); + return ret; + } } /* set the parameters and addresses */ @@ -307,7 +308,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) channel2_intr_assert(); channel2_intr_enable(1); enable_channel2(1); - if (vpif_config_data->ch2_clip_en) + if (vpif_config_data->chan_config[VPIF_CHANNEL2_VIDEO].clip_en) channel2_clipping_enable(1); } @@ -316,7 +317,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) channel3_intr_assert(); channel3_intr_enable(1); enable_channel3(1); - if (vpif_config_data->ch3_clip_en) + if (vpif_config_data->chan_config[VPIF_CHANNEL3_VIDEO].clip_en) channel3_clipping_enable(1); } @@ -826,9 +827,11 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); - strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpif_dev)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -935,6 +938,7 @@ static int vpif_reqbufs(struct file *file, void *priv, enum v4l2_field field; struct vb2_queue *q; u8 index = 0; + int ret; /* This file handle has not initialized the channel, It is not allowed to do settings */ @@ -980,8 +984,12 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); - vb2_queue_init(q); - + ret = vb2_queue_init(q); + if (ret) { + vpif_err("vpif_display: vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; /* Increment io usrs member of channel object to 1 */ @@ -1173,14 +1181,16 @@ static int vpif_streamoff(struct file *file, void *priv, if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - if (vpif_config_data->ch2_clip_en) + if (vpif_config_data-> + chan_config[VPIF_CHANNEL2_VIDEO].clip_en) channel2_clipping_enable(0); enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { - if (vpif_config_data->ch3_clip_en) + if (vpif_config_data-> + chan_config[VPIF_CHANNEL3_VIDEO].clip_en) channel3_clipping_enable(0); enable_channel3(0); channel3_intr_enable(0); @@ -1213,49 +1223,126 @@ static int vpif_enum_output(struct file *file, void *fh, { struct vpif_display_config *config = vpif_dev->platform_data; + struct vpif_display_chan_config *chan_cfg; + struct vpif_fh *vpif_handler = fh; + struct channel_obj *ch = vpif_handler->channel; - if (output->index >= config->output_count) { + chan_cfg = &config->chan_config[ch->channel_id]; + if (output->index >= chan_cfg->output_count) { vpif_dbg(1, debug, "Invalid output index\n"); return -EINVAL; } - strcpy(output->name, config->output[output->index]); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = VPIF_V4L2_STD; + *output = chan_cfg->outputs[output->index].output; + return 0; +} + +/** + * vpif_output_to_subdev() - Maps output to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr + * @index - Given output index from application + * + * lookup the sub device information for a given output index. + * we report all the output to application. output table also + * has sub device name for the each output + */ +static int +vpif_output_to_subdev(struct vpif_display_config *vpif_cfg, + struct vpif_display_chan_config *chan_cfg, int index) +{ + struct vpif_subdev_info *subdev_info; + const char *subdev_name; + int i; + + vpif_dbg(2, debug, "vpif_output_to_subdev\n"); + + if (chan_cfg->outputs == NULL) + return -1; + + subdev_name = chan_cfg->outputs[index].subdev_name; + if (subdev_name == NULL) + return -1; + + /* loop through the sub device list to get the sub device info */ + for (i = 0; i < vpif_cfg->subdev_count; i++) { + subdev_info = &vpif_cfg->subdevinfo[i]; + if (!strcmp(subdev_info->name, subdev_name)) + return i; + } + return -1; +} + +/** + * vpif_set_output() - Select an output + * @vpif_cfg - global config ptr + * @ch - channel + * @index - Given output index from application + * + * Select the given output. + */ +static int vpif_set_output(struct vpif_display_config *vpif_cfg, + struct channel_obj *ch, int index) +{ + struct vpif_display_chan_config *chan_cfg = + &vpif_cfg->chan_config[ch->channel_id]; + struct vpif_subdev_info *subdev_info = NULL; + struct v4l2_subdev *sd = NULL; + u32 input = 0, output = 0; + int sd_index; + int ret; + + sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index); + if (sd_index >= 0) { + sd = vpif_obj.sd[sd_index]; + subdev_info = &vpif_cfg->subdevinfo[sd_index]; + } + + if (sd) { + input = chan_cfg->outputs[index].input_route; + output = chan_cfg->outputs[index].output_route; + ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_err("Failed to set output\n"); + return ret; + } + } + ch->output_idx = index; + ch->sd = sd; + if (chan_cfg->outputs != NULL) + /* update tvnorms from the sub device output info */ + ch->video_dev->tvnorms = chan_cfg->outputs[index].output.std; return 0; } static int vpif_s_output(struct file *file, void *priv, unsigned int i) { + struct vpif_display_config *config = vpif_dev->platform_data; + struct vpif_display_chan_config *chan_cfg; struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (i >= chan_cfg->output_count) + return -EINVAL; if (common->started) { vpif_err("Streaming in progress\n"); return -EBUSY; } - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_routing, 0, i, 0); - - if (ret < 0) - vpif_err("Failed to set output standard\n"); - - vid_ch->output_id = i; - return ret; + return vpif_set_output(config, ch, i); } static int vpif_g_output(struct file *file, void *priv, unsigned int *i) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - *i = vid_ch->output_id; + *i = ch->output_idx; return 0; } @@ -1290,10 +1377,12 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; + int ret; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, enum_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -EINVAL; + return ret; } /** @@ -1319,13 +1408,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } + ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + ret = 0; if (ret < 0) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; @@ -1450,10 +1535,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg){ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, - g_register, reg); + return v4l2_subdev_call(ch->sd, core, g_register, reg); } /* @@ -1469,10 +1552,8 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct v4l2_dbg_register *reg){ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, - s_register, reg); + return v4l2_subdev_call(ch->sd, core, s_register, reg); } #endif @@ -1536,9 +1617,6 @@ static struct video_device vpif_video_template = { .name = "vpif", .fops = &vpif_fops, .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = VPIF_V4L2_STD, - .current_norm = V4L2_STD_625_50, - }; /*Configure the channels, buffer sizei, request irq */ @@ -1611,7 +1689,8 @@ static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct vpif_display_config *config; - int i, j = 0, k, q, m, err = 0; + int i, j = 0, k, err = 0; + int res_idx = 0; struct i2c_adapter *i2c_adap; struct common_obj *common; struct channel_obj *ch; @@ -1634,21 +1713,22 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, vpif_channel_isr, IRQF_SHARED, - "VPIF_Display", - (void *)(&vpif_obj.dev[k]->channel_id))) { + "VPIF_Display", (void *) + (&vpif_obj.dev[res_idx]->channel_id))) { err = -EBUSY; + for (j = 0; j < i; j++) + free_irq(j, (void *) + (&vpif_obj.dev[res_idx]->channel_id)); goto vpif_int_err; } } - k++; + res_idx++; } for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ ch = vpif_obj.dev[i]; @@ -1694,6 +1774,32 @@ static __init int vpif_probe(struct platform_device *pdev) } } + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + subdev_count = config->subdev_count; + subdevdata = config->subdevinfo; + vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto vpif_sd_error; + } + + for (i = 0; i < subdev_count; i++) { + vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, + &subdevdata[i].board_info, + NULL); + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; /* Initialize field of the channel objects */ @@ -1715,6 +1821,8 @@ static __init int vpif_probe(struct platform_device *pdev) } ch->initialized = 0; + if (subdev_count) + ch->sd = vpif_obj.sd[0]; ch->channel_id = j; if (j < 2) ch->common[VPIF_VIDEO_INDEX].numbuffers = @@ -1729,6 +1837,12 @@ static __init int vpif_probe(struct platform_device *pdev) ch->common[VPIF_VIDEO_INDEX].fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ch->video_dev->lock = &common->lock; + video_set_drvdata(ch->video_dev, ch); + + /* select output 0 */ + err = vpif_set_output(config, ch, 0); + if (err) + goto probe_out; /* register video device */ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", @@ -1738,42 +1852,12 @@ static __init int vpif_probe(struct platform_device *pdev) VFL_TYPE_GRABBER, (j ? 3 : 2)); if (err < 0) goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - subdev_count = config->subdev_count; - subdevdata = config->subdevinfo; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - for (i = 0; i < subdev_count; i++) { - vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, - &subdevdata[i].board_info, - NULL); - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; } v4l2_info(&vpif_obj.v4l2_dev, " VPIF display driver initialized\n"); return 0; -probe_subdev_out: - kfree(vpif_obj.sd); probe_out: for (k = 0; k < j; k++) { ch = vpif_obj.dev[k]; @@ -1781,14 +1865,21 @@ probe_out: video_device_release(ch->video_dev); ch->video_dev = NULL; } +probe_subdev_out: + kfree(vpif_obj.sd); +vpif_sd_error: + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + ch = vpif_obj.dev[i]; + /* Note: does nothing if ch->video_dev == NULL */ + video_device_release(ch->video_dev); + } vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); vpif_err("VPIF IRQ request failed\n"); - for (q = k; k >= 0; k--) { - for (m = i; m >= res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); - res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); - m = res->end; + for (i = 0; i < res_idx; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + for (j = res->start; j <= res->end; j++) + free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); } return err; diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index f628ebcf3674..a5a18f74395c 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -62,13 +62,6 @@ struct video_obj { v4l2_std_id stdid; /* Currently selected or default * standard */ struct v4l2_dv_timings dv_timings; - u32 output_id; /* Current output id */ -}; - -struct vbi_obj { - int num_services; - struct vpif_vbi_params vbiparams; /* vpif parameters for the raw - * vbi data */ }; struct vpif_disp_buffer { @@ -131,12 +124,13 @@ struct channel_obj { * which is being displayed */ u8 initialized; /* flag to indicate whether * encoder is initialized */ + u32 output_idx; /* Current output index */ + struct v4l2_subdev *sd; /* Current output subdev(may be NULL) */ enum vpif_channel_id channel_id;/* Identifies channel */ struct vpif_params vpifparams; struct common_obj common[VPIF_NUMOBJECTS]; struct video_obj video; - struct vbi_obj vbi; }; /* File handle structure */ @@ -168,12 +162,4 @@ struct vpif_config_params { u8 min_numbuffers; }; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; - u16 enc_service_id; - u8 bytestowrite; -}; - #endif /* DAVINCIHD_DISPLAY_H */ diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index 0d8625f03a32..0146b354dc22 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.c +++ b/drivers/media/platform/exynos-gsc/gsc-regs.c @@ -212,7 +212,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx) else cfg |= GSC_IN_YUV422_3P; break; - }; + } writel(cfg, dev->regs + GSC_IN_CON); } @@ -332,7 +332,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx) case 3: cfg |= GSC_OUT_YUV420_3P; break; - }; + } end_set: writel(cfg, dev->regs + GSC_OUT_CON); diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 897250b88647..31ac4dc69247 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -864,7 +864,7 @@ int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer * { struct viu_fh *fh = priv; struct viu_dev *dev = fh->dev; - struct v4l2_framebuffer *fb = arg; + const struct v4l2_framebuffer *fb = arg; struct viu_fmt *fmt; if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index d03637537118..2e2121e98133 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -397,8 +397,7 @@ static void device_isr(unsigned long priv) curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev); if (NULL == curr_ctx) { - printk(KERN_ERR - "Instance released before the end of transaction\n"); + pr_err("Instance released before the end of transaction\n"); return; } @@ -894,7 +893,7 @@ static int m2mtest_open(struct file *file) if (mutex_lock_interruptible(&dev->dev_mutex)) return -ERESTARTSYS; - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { rc = -ENOMEM; goto open_unlock; @@ -1020,7 +1019,7 @@ static int m2mtest_probe(struct platform_device *pdev) struct video_device *vfd; int ret; - dev = kzalloc(sizeof *dev, GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1028,7 +1027,7 @@ static int m2mtest_probe(struct platform_device *pdev) ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - goto free_dev; + return ret; atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); @@ -1067,15 +1066,13 @@ static int m2mtest_probe(struct platform_device *pdev) return 0; - v4l2_m2m_release(dev->m2m_dev); err_m2m: + v4l2_m2m_release(dev->m2m_dev); video_unregister_device(dev->vfd); rel_vdev: video_device_release(vfd); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); return ret; } @@ -1090,7 +1087,6 @@ static int m2mtest_remove(struct platform_device *pdev) del_timer_sync(&dev->timer); video_unregister_device(dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); return 0; } diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 134016f0e660..a3b1a34c896d 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -455,11 +455,15 @@ static int omapvid_init(struct omap_vout_device *vout, u32 addr) win = &vout->win; for (i = 0; i < ovid->num_overlays; i++) { + struct omap_dss_device *dssdev; + ovl = ovid->overlays[i]; - if (!ovl->manager || !ovl->manager->device) + dssdev = ovl->get_device(ovl); + + if (!dssdev) return -EINVAL; - timing = &ovl->manager->device->panel.timings; + timing = &dssdev->panel.timings; outw = win->w.width; outh = win->w.height; @@ -516,8 +520,11 @@ static int omapvid_apply_changes(struct omap_vout_device *vout) struct omapvideo_info *ovid = &vout->vid_info; for (i = 0; i < ovid->num_overlays; i++) { + struct omap_dss_device *dssdev; + ovl = ovid->overlays[i]; - if (!ovl->manager || !ovl->manager->device) + dssdev = ovl->get_device(ovl); + if (!dssdev) return -EINVAL; ovl->manager->apply(ovl->manager); } @@ -580,12 +587,14 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) ovid = &vout->vid_info; ovl = ovid->overlays[0]; - /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) - return; mgr_id = ovl->manager->id; - cur_display = ovl->manager->device; + + /* get the display device attached to the overlay */ + cur_display = ovl->get_device(ovl); + + if (!cur_display) + return; spin_lock(&vout->vbq_lock); do_gettimeofday(&timevalue); @@ -949,7 +958,9 @@ static int omap_vout_release(struct file *file) /* Disable all the overlay managers connected with this interface */ for (i = 0; i < ovid->num_overlays; i++) { struct omap_overlay *ovl = ovid->overlays[i]; - if (ovl->manager && ovl->manager->device) + struct omap_dss_device *dssdev = ovl->get_device(ovl); + + if (dssdev) ovl->disable(ovl); } /* Turn off the pipeline */ @@ -1082,14 +1093,17 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *fh, struct omapvideo_info *ovid; struct omap_video_timings *timing; struct omap_vout_device *vout = fh; + struct omap_dss_device *dssdev; ovid = &vout->vid_info; ovl = ovid->overlays[0]; + /* get the display device attached to the overlay */ + dssdev = ovl->get_device(ovl); - if (!ovl->manager || !ovl->manager->device) + if (!dssdev) return -EINVAL; - /* get the display device attached to the overlay */ - timing = &ovl->manager->device->panel.timings; + + timing = &dssdev->panel.timings; vout->fbuf.fmt.height = timing->y_res; vout->fbuf.fmt.width = timing->x_res; @@ -1106,6 +1120,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, struct omapvideo_info *ovid; struct omap_video_timings *timing; struct omap_vout_device *vout = fh; + struct omap_dss_device *dssdev; if (vout->streaming) return -EBUSY; @@ -1114,13 +1129,14 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, ovid = &vout->vid_info; ovl = ovid->overlays[0]; + dssdev = ovl->get_device(ovl); /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) { + if (!dssdev) { ret = -EINVAL; goto s_fmt_vid_out_exit; } - timing = &ovl->manager->device->panel.timings; + timing = &dssdev->panel.timings; /* We dont support RGB24-packed mode if vrfb rotation * is enabled*/ @@ -1299,6 +1315,7 @@ static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr struct omapvideo_info *ovid; struct omap_overlay *ovl; struct omap_video_timings *timing; + struct omap_dss_device *dssdev; if (vout->streaming) return -EBUSY; @@ -1306,13 +1323,15 @@ static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr mutex_lock(&vout->lock); ovid = &vout->vid_info; ovl = ovid->overlays[0]; + /* get the display device attached to the overlay */ + dssdev = ovl->get_device(ovl); - if (!ovl->manager || !ovl->manager->device) { + if (!dssdev) { ret = -EINVAL; goto s_crop_err; } - /* get the display device attached to the overlay */ - timing = &ovl->manager->device->panel.timings; + + timing = &dssdev->panel.timings; if (is_rotation_90_or_270(vout)) { vout->fbuf.fmt.height = timing->x_res; @@ -1668,7 +1687,7 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; - if (ovl->manager && ovl->manager->device) { + if (ovl->get_device(ovl)) { struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); info.paddr = addr; @@ -1691,8 +1710,9 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; + struct omap_dss_device *dssdev = ovl->get_device(ovl); - if (ovl->manager && ovl->manager->device) { + if (dssdev) { ret = ovl->enable(ovl); if (ret) goto streamon_err1; @@ -1727,8 +1747,9 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; + struct omap_dss_device *dssdev = ovl->get_device(ovl); - if (ovl->manager && ovl->manager->device) + if (dssdev) ovl->disable(ovl); } @@ -1891,8 +1912,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) struct video_device *vfd; struct v4l2_pix_format *pix; struct v4l2_control *control; - struct omap_dss_device *display = - vout->vid_info.overlays[0]->manager->device; + struct omap_overlay *ovl = vout->vid_info.overlays[0]; + struct omap_dss_device *display = ovl->get_device(ovl); /* set the default pix */ pix = &vout->pix; @@ -2207,8 +2228,10 @@ static int __init omap_vout_probe(struct platform_device *pdev) */ for (i = 1; i < vid_dev->num_overlays; i++) { ovl = omap_dss_get_overlay(i); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; + dssdev = ovl->get_device(ovl); + + if (dssdev) { + def_display = dssdev; } else { dev_warn(&pdev->dev, "cannot find display\n"); def_display = NULL; @@ -2255,8 +2278,10 @@ probe_err1: for (i = 1; i < vid_dev->num_overlays; i++) { def_display = NULL; ovl = omap_dss_get_overlay(i); - if (ovl->manager && ovl->manager->device) - def_display = ovl->manager->device; + dssdev = ovl->get_device(ovl); + + if (dssdev) + def_display = dssdev; if (def_display && def_display->driver) def_display->driver->disable(def_display); diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index 084ea77d65a7..e2c57f334c5d 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -27,13 +27,13 @@ #ifndef OMAP3_ISP_REG_H #define OMAP3_ISP_REG_H -#include <plat/omap34xx.h> - - #define CM_CAM_MCLK_HZ 172800000 /* Hz */ /* ISP Submodules offset */ +#define L4_34XX_BASE 0x48000000 +#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) + #define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE #define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset)) diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index dded98815220..367efd164d0f 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -177,7 +177,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { + struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_frame *f = &cap->ctx->d_frame; struct fimc_vid_buffer *v_buf; struct timeval *tv; struct timespec ts; @@ -216,6 +218,25 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } + /* + * Set up a buffer at MIPI-CSIS if current image format + * requires the frame embedded data capture. + */ + if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { + unsigned int plane = ffs(f->fmt->mdataplanes) - 1; + unsigned int size = f->payload[plane]; + s32 index = fimc_hw_get_frame_index(fimc); + void *vaddr; + + list_for_each_entry(v_buf, &cap->active_buf_q, list) { + if (v_buf->index != index) + continue; + vaddr = vb2_plane_vaddr(&v_buf->vb, plane); + v4l2_subdev_call(csis, video, s_rx_buffer, + vaddr, &size); + break; + } + } if (cap->active_buf_cnt == 0) { if (deq_buf) @@ -351,6 +372,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, unsigned int size = (wh * fmt->depth[i]) / 8; if (pixm) sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); + else if (fimc_fmt_is_user_defined(fmt->color)) + sizes[i] = frame->payload[i]; else sizes[i] = max_t(u32, size, frame->payload[i]); @@ -611,10 +634,10 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, u32 mask = FMT_FLAGS_CAM; struct fimc_fmt *ffmt; - /* Color conversion from/to JPEG is not supported */ + /* Conversion from/to JPEG or User Defined format is not supported */ if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && - fimc_fmt_is_jpeg(ctx->s_frame.fmt->color)) - *code = V4L2_MBUS_FMT_JPEG_1X8; + fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) + *code = ctx->s_frame.fmt->mbus_code; if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) mask |= FMT_FLAGS_M2M; @@ -628,18 +651,19 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, *fourcc = ffmt->fourcc; if (pad == FIMC_SD_PAD_SINK) { - max_w = fimc_fmt_is_jpeg(ffmt->color) ? + max_w = fimc_fmt_is_user_defined(ffmt->color) ? pl->scaler_dis_w : pl->scaler_en_w; /* Apply the camera input interface pixel constraints */ v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, height, max_t(u32, *height, 32), FIMC_CAMIF_MAX_HEIGHT, - fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1, + fimc_fmt_is_user_defined(ffmt->color) ? + 3 : 1, 0); return ffmt; } /* Can't scale or crop in transparent (JPEG) transfer mode */ - if (fimc_fmt_is_jpeg(ffmt->color)) { + if (fimc_fmt_is_user_defined(ffmt->color)) { *width = ctx->s_frame.f_width; *height = ctx->s_frame.f_height; return ffmt; @@ -684,7 +708,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, u32 max_sc_h, max_sc_v; /* In JPEG transparent transfer mode cropping is not supported */ - if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) { + if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) { r->width = sink->f_width; r->height = sink->f_height; r->left = r->top = 0; @@ -847,6 +871,48 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, return 0; } +/** + * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters + * @sensor: pointer to the sensor subdev + * @plane_fmt: provides plane sizes corresponding to the frame layout entries + * @try: true to set the frame parameters, false to query only + * + * This function is used by this driver only for compressed/blob data formats. + */ +static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, + struct v4l2_plane_pix_format *plane_fmt, + unsigned int num_planes, bool try) +{ + struct v4l2_mbus_frame_desc fd; + int i, ret; + + for (i = 0; i < num_planes; i++) + fd.entry[i].length = plane_fmt[i].sizeimage; + + if (try) + ret = v4l2_subdev_call(sensor, pad, set_frame_desc, 0, &fd); + else + ret = v4l2_subdev_call(sensor, pad, get_frame_desc, 0, &fd); + + if (ret < 0) + return ret; + + if (num_planes != fd.num_entries) + return -EINVAL; + + for (i = 0; i < num_planes; i++) + plane_fmt[i].sizeimage = fd.entry[i].length; + + if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) { + v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n", + fd.entry[0].length); + + return -EINVAL; + } + + return 0; +} + static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { @@ -865,7 +931,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct v4l2_mbus_framefmt mf; struct fimc_fmt *ffmt = NULL; - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK); @@ -879,25 +945,32 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, return -EINVAL; if (!fimc->vid_cap.user_subdev_api) { - mf.width = pix->width; + mf.width = pix->width; mf.height = pix->height; - mf.code = ffmt->mbus_code; + mf.code = ffmt->mbus_code; fimc_md_graph_lock(fimc); fimc_pipeline_try_format(ctx, &mf, &ffmt, false); fimc_md_graph_unlock(fimc); - - pix->width = mf.width; - pix->height = mf.height; + pix->width = mf.width; + pix->height = mf.height; if (ffmt) pix->pixelformat = ffmt->fourcc; } fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); + + if (ffmt->flags & FMT_FLAGS_COMPRESSED) + fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ffmt->memplanes, true); + return 0; } -static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg) +static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, + enum fimc_color_fmt color) { + bool jpeg = fimc_fmt_is_user_defined(color); + ctx->scaler.enabled = !jpeg; fimc_ctrls_activate(ctx, !jpeg); @@ -920,7 +993,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) return -EBUSY; /* Pre-configure format at camera interface input, for JPEG only */ - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK); @@ -953,7 +1026,16 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) } fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); - for (i = 0; i < ff->fmt->colplanes; i++) + + if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { + ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ff->fmt->memplanes, + true); + if (ret < 0) + return ret; + } + + for (i = 0; i < ff->fmt->memplanes; i++) ff->payload[i] = pix->plane_fmt[i].sizeimage; set_frame_bounds(ff, pix->width, pix->height); @@ -961,7 +1043,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) if (!(ctx->state & FIMC_COMPOSE)) set_frame_crop(ff, 0, 0, pix->width, pix->height); - fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color)); + fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color); /* Reset cropping and set format at the camera interface input */ if (!fimc->vid_cap.user_subdev_api) { @@ -1063,6 +1145,23 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) src_fmt.format.height != sink_fmt.format.height || src_fmt.format.code != sink_fmt.format.code) return -EPIPE; + + if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && + fimc_user_defined_mbus_fmt(src_fmt.format.code)) { + struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; + struct fimc_frame *frame = &vid_cap->ctx->d_frame; + unsigned int i; + + ret = fimc_get_sensor_frame_desc(sd, plane_fmt, + frame->fmt->memplanes, + false); + if (ret < 0) + return -EPIPE; + + for (i = 0; i < frame->fmt->memplanes; i++) + if (frame->payload[i] < plane_fmt[i].sizeimage) + return -EPIPE; + } } return 0; } @@ -1424,7 +1523,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, /* Update RGB Alpha control state and value range */ fimc_alpha_ctrl_update(ctx); - fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); + fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 1a445404e73d..8d0d2b94a135 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -184,7 +184,17 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 1, .colplanes = 1, .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, - .flags = FMT_FLAGS_CAM, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, + }, { + .name = "S5C73MX interleaved UYVY/JPEG", + .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, + .color = FIMC_FMT_YUYV_JPEG, + .depth = { 8 }, + .memplanes = 2, + .colplanes = 1, + .mdataplanes = 0x2, /* plane 1 holds frame meta data */ + .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, }; @@ -371,7 +381,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, default: return -EINVAL; } - } else { + } else if (!frame->fmt->mdataplanes) { if (frame->fmt->memplanes >= 2) paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); @@ -698,6 +708,11 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f) if (frame->fmt->colplanes == 1) /* packed formats */ bpl = (bpl * frame->fmt->depth[0]) / 8; pixm->plane_fmt[i].bytesperline = bpl; + + if (frame->fmt->flags & FMT_FLAGS_COMPRESSED) { + pixm->plane_fmt[i].sizeimage = frame->payload[i]; + continue; + } pixm->plane_fmt[i].sizeimage = (frame->o_width * frame->o_height * frame->fmt->depth[i]) / 8; } diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index cd716ba6015f..c0040d792499 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -40,6 +40,8 @@ #define SCALER_MAX_VRATIO 64 #define DMA_MIN_SIZE 8 #define FIMC_CAMIF_MAX_HEIGHT 0x2000 +#define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M) +#define FIMC_MAX_PLANES 3 /* indices to the clocks array */ enum { @@ -83,7 +85,7 @@ enum fimc_datapath { }; enum fimc_color_fmt { - FIMC_FMT_RGB444 = 0x10, + FIMC_FMT_RGB444 = 0x10, FIMC_FMT_RGB555, FIMC_FMT_RGB565, FIMC_FMT_RGB666, @@ -95,14 +97,15 @@ enum fimc_color_fmt { FIMC_FMT_CBYCRY422, FIMC_FMT_CRYCBY422, FIMC_FMT_YCBCR444_LOCAL, - FIMC_FMT_JPEG = 0x40, - FIMC_FMT_RAW8 = 0x80, + FIMC_FMT_RAW8 = 0x40, FIMC_FMT_RAW10, FIMC_FMT_RAW12, + FIMC_FMT_JPEG = 0x80, + FIMC_FMT_YUYV_JPEG = 0x100, }; +#define fimc_fmt_is_user_defined(x) (!!((x) & 0x180)) #define fimc_fmt_is_rgb(x) (!!((x) & 0x10)) -#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40)) #define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -139,6 +142,7 @@ enum fimc_color_fmt { * @memplanes: number of physically non-contiguous data planes * @colplanes: number of physically contiguous data planes * @depth: per plane driver's private 'number of bits per pixel' + * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) * @flags: flags indicating which operation mode format applies to */ struct fimc_fmt { @@ -149,12 +153,14 @@ struct fimc_fmt { u16 memplanes; u16 colplanes; u8 depth[VIDEO_MAX_PLANES]; + u16 mdataplanes; u16 flags; #define FMT_FLAGS_CAM (1 << 0) #define FMT_FLAGS_M2M_IN (1 << 1) #define FMT_FLAGS_M2M_OUT (1 << 2) #define FMT_FLAGS_M2M (1 << 1 | 1 << 2) #define FMT_HAS_ALPHA (1 << 3) +#define FMT_FLAGS_COMPRESSED (1 << 4) }; /** @@ -272,7 +278,7 @@ struct fimc_frame { u32 offs_v; u32 width; u32 height; - unsigned long payload[VIDEO_MAX_PLANES]; + unsigned int payload[VIDEO_MAX_PLANES]; struct fimc_addr paddr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; @@ -577,6 +583,18 @@ static inline int tiled_fmt(struct fimc_fmt *fmt) return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } +static inline bool fimc_jpeg_fourcc(u32 pixelformat) +{ + return (pixelformat == V4L2_PIX_FMT_JPEG || + pixelformat == V4L2_PIX_FMT_S5C_UYVY_JPG); +} + +static inline bool fimc_user_defined_mbus_fmt(u32 code) +{ + return (code == V4L2_MBUS_FMT_JPEG_1X8 || + code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8); +} + /* Return the alpha component bit mask */ static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) { diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index 6b71d953fd15..4500e44f6857 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -551,30 +551,31 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return 0; } -static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr) +static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_crop cr = *crop; struct fimc_frame *f; int ret; - ret = fimc_m2m_try_crop(ctx, cr); + ret = fimc_m2m_try_crop(ctx, &cr); if (ret) return ret; - f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? + f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->s_frame : &ctx->d_frame; /* Check to see if scaling ratio is within supported range */ if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(ctx, cr->c.width, - cr->c.height, ctx->d_frame.width, + if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = fimc_check_scaler_ratio(ctx, cr.c.width, + cr.c.height, ctx->d_frame.width, ctx->d_frame.height, ctx->rotation); } else { ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, - ctx->s_frame.height, cr->c.width, - cr->c.height, ctx->rotation); + ctx->s_frame.height, cr.c.width, + cr.c.height, ctx->rotation); } if (ret) { v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); @@ -582,10 +583,10 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop * } } - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; + f->offs_h = cr.c.left; + f->offs_v = cr.c.top; + f->width = cr.c.width; + f->height = cr.c.height; fimc_ctx_state_set(FIMC_PARAMS, ctx); diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c index 783408fd7d56..2c9d0c06c9e8 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-reg.c @@ -625,7 +625,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; } /* else defaults to ITU-R BT.656 8-bit */ } else if (cam->bus_type == FIMC_MIPI_CSI2) { - if (fimc_fmt_is_jpeg(f->fmt->color)) + if (fimc_fmt_is_user_defined(f->fmt->color)) cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; } @@ -680,6 +680,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; break; case V4L2_MBUS_FMT_JPEG_1X8: + case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: tmp = FIMC_REG_CSIIMGFMT_USER(1); cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; break; @@ -744,13 +745,13 @@ void fimc_hw_dis_capture(struct fimc_dev *dev) } /* Return an index to the buffer actually being written. */ -u32 fimc_hw_get_frame_index(struct fimc_dev *dev) +s32 fimc_hw_get_frame_index(struct fimc_dev *dev) { - u32 reg; + s32 reg; if (dev->variant->has_cistatus2) { - reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3F; - return reg > 0 ? --reg : reg; + reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; + return reg - 1; } reg = readl(dev->regs + FIMC_REG_CISTATUS); @@ -759,6 +760,18 @@ u32 fimc_hw_get_frame_index(struct fimc_dev *dev) FIMC_REG_CISTATUS_FRAMECNT_SHIFT; } +/* Return an index to the buffer being written previously. */ +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) +{ + s32 reg; + + if (!dev->variant->has_cistatus2) + return -1; + + reg = readl(dev->regs + FIMC_REG_CISTATUS2); + return ((reg >> 7) & 0x3f) - 1; +} + /* Locking: the caller holds fimc->slock */ void fimc_activate_capture(struct fimc_ctx *ctx) { diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h index 579ac8ac03de..b6abfc7b72ac 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.h +++ b/drivers/media/platform/s5p-fimc/fimc-reg.h @@ -307,7 +307,8 @@ void fimc_hw_clear_irq(struct fimc_dev *dev); void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on); void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); void fimc_hw_dis_capture(struct fimc_dev *dev); -u32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev); void fimc_activate_capture(struct fimc_ctx *ctx); void fimc_deactivate_capture(struct fimc_dev *fimc); diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index e92236ac5cfe..4c961b1b68e6 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -2,7 +2,7 @@ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver * * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki, <s.nawrocki@samsung.com> + * Sylwester Nawrocki <s.nawrocki@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -98,6 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); #define CSIS_MAX_PIX_WIDTH 0xffff #define CSIS_MAX_PIX_HEIGHT 0xffff +/* Non-image packet data buffers */ +#define S5PCSIS_PKTDATA_ODD 0x2000 +#define S5PCSIS_PKTDATA_EVEN 0x3000 +#define S5PCSIS_PKTDATA_SIZE SZ_4K + enum { CSIS_CLK_MUX, CSIS_CLK_GATE, @@ -110,8 +115,8 @@ static char *csi_clock_name[] = { #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) static const char * const csis_supply_name[] = { - "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */ - "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */ + "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ + "vddio", /* CSIS I/O and PLL (1.8V) supply */ }; #define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) @@ -144,12 +149,18 @@ static const struct s5pcsis_event s5pcsis_events[] = { }; #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) +struct csis_pktbuf { + u32 *data; + unsigned int len; +}; + /** * struct csis_state - the driver's internal state data structure * @lock: mutex serializing the subdev and power management operations, * protecting @format and @flags members * @pads: CSIS pads array * @sd: v4l2_subdev associated with CSIS device instance + * @index: the hardware instance index * @pdev: CSIS platform device * @regs: mmaped I/O registers memory * @supplies: CSIS regulator supplies @@ -159,12 +170,14 @@ static const struct s5pcsis_event s5pcsis_events[] = { * @csis_fmt: current CSIS pixel format * @format: common media bus format for the source and sink pad * @slock: spinlock protecting structure members below + * @pkt_buf: the frame embedded (non-image) data buffer * @events: MIPI-CSIS event (error) counters */ struct csis_state { struct mutex lock; struct media_pad pads[CSIS_PADS_NUM]; struct v4l2_subdev sd; + u8 index; struct platform_device *pdev; void __iomem *regs; struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; @@ -175,6 +188,7 @@ struct csis_state { struct v4l2_mbus_framefmt format; struct spinlock slock; + struct csis_pktbuf pkt_buf; struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; }; @@ -202,7 +216,11 @@ static const struct csis_pix_format s5pcsis_formats[] = { .code = V4L2_MBUS_FMT_JPEG_1X8, .fmt_reg = S5PCSIS_CFG_FMT_USER(1), .data_alignment = 32, - }, + }, { + .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .fmt_reg = S5PCSIS_CFG_FMT_USER(1), + .data_alignment = 32, + } }; #define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) @@ -266,7 +284,7 @@ static void __s5pcsis_set_format(struct csis_state *state) struct v4l2_mbus_framefmt *mf = &state->format; u32 val; - v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n", + v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n", mf->code, mf->width, mf->height); /* Color format */ @@ -304,8 +322,10 @@ static void s5pcsis_set_params(struct csis_state *state) val |= S5PCSIS_CTRL_ALIGN_32BIT; else /* 24-bits */ val &= ~S5PCSIS_CTRL_ALIGN_32BIT; - /* Not using external clock. */ + val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; + if (pdata->wclk_source) + val |= S5PCSIS_CTRL_WCLK_EXTCLK; s5pcsis_write(state, S5PCSIS_CTRL, val); /* Update the shadow register. */ @@ -529,6 +549,22 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } +static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf, + unsigned int *size) +{ + struct csis_state *state = sd_to_csis_state(sd); + unsigned long flags; + + *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE); + + spin_lock_irqsave(&state->slock, flags); + state->pkt_buf.data = buf; + state->pkt_buf.len = *size; + spin_unlock_irqrestore(&state->slock, flags); + + return 0; +} + static int s5pcsis_log_status(struct v4l2_subdev *sd) { struct csis_state *state = sd_to_csis_state(sd); @@ -566,6 +602,7 @@ static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { }; static struct v4l2_subdev_video_ops s5pcsis_video_ops = { + .s_rx_buffer = s5pcsis_s_rx_buffer, .s_stream = s5pcsis_s_stream, }; @@ -578,13 +615,26 @@ static struct v4l2_subdev_ops s5pcsis_subdev_ops = { static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) { struct csis_state *state = dev_id; + struct csis_pktbuf *pktbuf = &state->pkt_buf; unsigned long flags; u32 status; status = s5pcsis_read(state, S5PCSIS_INTSRC); - spin_lock_irqsave(&state->slock, flags); + if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { + u32 offset; + + if (status & S5PCSIS_INTSRC_EVEN) + offset = S5PCSIS_PKTDATA_EVEN; + else + offset = S5PCSIS_PKTDATA_ODD; + + memcpy(pktbuf->data, state->regs + offset, pktbuf->len); + pktbuf->data = NULL; + rmb(); + } + /* Update the event/error counters */ if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { int i; @@ -620,14 +670,15 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) spin_lock_init(&state->slock); state->pdev = pdev; + state->index = max(0, pdev->id); pdata = pdev->dev.platform_data; - if (pdata == NULL || pdata->phy_enable == NULL) { + if (pdata == NULL) { dev_err(&pdev->dev, "Platform data not fully specified\n"); return -EINVAL; } - if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || + if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) || pdata->lanes > CSIS0_MAX_LANES) { dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", pdata->lanes); @@ -710,7 +761,6 @@ e_clkput: static int s5pcsis_pm_suspend(struct device *dev, bool runtime) { - struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csis_state *state = sd_to_csis_state(sd); @@ -722,7 +772,7 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime) mutex_lock(&state->lock); if (state->flags & ST_POWERED) { s5pcsis_stop_stream(state); - ret = pdata->phy_enable(state->pdev, false); + ret = s5p_csis_phy_enable(state->index, false); if (ret) goto unlock; ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, @@ -741,7 +791,6 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime) static int s5pcsis_pm_resume(struct device *dev, bool runtime) { - struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csis_state *state = sd_to_csis_state(sd); @@ -759,7 +808,7 @@ static int s5pcsis_pm_resume(struct device *dev, bool runtime) state->supplies); if (ret) goto unlock; - ret = pdata->phy_enable(state->pdev, true); + ret = s5p_csis_phy_enable(state->index, true); if (!ret) { state->flags |= ST_POWERED; } else { diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 1e3b9dd014c0..1bfbc325836b 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -507,7 +507,7 @@ static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr) return 0; } -static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr) +static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop *cr) { struct g2d_ctx *ctx = prv; struct g2d_dev *dev = ctx->dev; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 394775ae5774..17983c4c9a9a 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1353,7 +1353,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) return ret; } dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); - clk_enable(jpeg->clk); + clk_prepare_enable(jpeg->clk); /* v4l2 device */ ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); @@ -1460,7 +1460,7 @@ device_register_rollback: v4l2_device_unregister(&jpeg->v4l2_dev); clk_get_rollback: - clk_disable(jpeg->clk); + clk_disable_unprepare(jpeg->clk); clk_put(jpeg->clk); return ret; @@ -1480,7 +1480,7 @@ static int s5p_jpeg_remove(struct platform_device *pdev) v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); - clk_disable(jpeg->clk); + clk_disable_unprepare(jpeg->clk); clk_put(jpeg->clk); return 0; diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index d0663409af00..379008c6d09a 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o -s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o +s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o -s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o -s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o +s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o +s5p-mfc-y += s5p_mfc_opr.o s5p_mfc_opr_v5.o s5p_mfc_opr_v6.o +s5p-mfc-y += s5p_mfc_cmd.o s5p_mfc_cmd_v5.o s5p_mfc_cmd_v6.o diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h new file mode 100644 index 000000000000..363a97cc7681 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -0,0 +1,408 @@ +/* + * Register definition file for Samsung MFC V6.x Interface (FIMV) driver + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _REGS_FIMV_V6_H +#define _REGS_FIMV_V6_H + +#include <linux/kernel.h> +#include <linux/sizes.h> + +#define S5P_FIMV_REG_SIZE_V6 (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) +#define S5P_FIMV_REG_COUNT_V6 ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) + +/* Number of bits that the buffer address should be shifted for particular + * MFC buffers. */ +#define S5P_FIMV_MEM_OFFSET_V6 0 + +#define S5P_FIMV_START_ADDR_V6 0x0000 +#define S5P_FIMV_END_ADDR_V6 0xfd80 + +#define S5P_FIMV_REG_CLEAR_BEGIN_V6 0xf000 +#define S5P_FIMV_REG_CLEAR_COUNT_V6 1024 + +/* Codec Common Registers */ +#define S5P_FIMV_RISC_ON_V6 0x0000 +#define S5P_FIMV_RISC2HOST_INT_V6 0x003C +#define S5P_FIMV_HOST2RISC_INT_V6 0x0044 +#define S5P_FIMV_RISC_BASE_ADDRESS_V6 0x0054 + +#define S5P_FIMV_MFC_RESET_V6 0x1070 + +#define S5P_FIMV_HOST2RISC_CMD_V6 0x1100 +#define S5P_FIMV_H2R_CMD_EMPTY_V6 0 +#define S5P_FIMV_H2R_CMD_SYS_INIT_V6 1 +#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6 2 +#define S5P_FIMV_CH_SEQ_HEADER_V6 3 +#define S5P_FIMV_CH_INIT_BUFS_V6 4 +#define S5P_FIMV_CH_FRAME_START_V6 5 +#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6 6 +#define S5P_FIMV_H2R_CMD_SLEEP_V6 7 +#define S5P_FIMV_H2R_CMD_WAKEUP_V6 8 +#define S5P_FIMV_CH_LAST_FRAME_V6 9 +#define S5P_FIMV_H2R_CMD_FLUSH_V6 10 +/* RMVME: REALLOC used? */ +#define S5P_FIMV_CH_FRAME_START_REALLOC_V6 5 + +#define S5P_FIMV_RISC2HOST_CMD_V6 0x1104 +#define S5P_FIMV_R2H_CMD_EMPTY_V6 0 +#define S5P_FIMV_R2H_CMD_SYS_INIT_RET_V6 1 +#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET_V6 2 +#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET_V6 3 +#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET_V6 4 + +#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET_V6 6 +#define S5P_FIMV_R2H_CMD_SLEEP_RET_V6 7 +#define S5P_FIMV_R2H_CMD_WAKEUP_RET_V6 8 +#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET_V6 9 +#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET_V6 10 +#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET_V6 11 +#define S5P_FIMV_R2H_CMD_FW_STATUS_RET_V6 12 +#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET_V6 13 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET_V6 14 +#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET_V6 15 +#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16 +#define S5P_FIMV_R2H_CMD_ERR_RET_V6 32 + +#define S5P_FIMV_FW_VERSION_V6 0xf000 + +#define S5P_FIMV_INSTANCE_ID_V6 0xf008 +#define S5P_FIMV_CODEC_TYPE_V6 0xf00c +#define S5P_FIMV_CONTEXT_MEM_ADDR_V6 0xf014 +#define S5P_FIMV_CONTEXT_MEM_SIZE_V6 0xf018 +#define S5P_FIMV_PIXEL_FORMAT_V6 0xf020 + +#define S5P_FIMV_METADATA_ENABLE_V6 0xf024 +#define S5P_FIMV_DBG_BUFFER_ADDR_V6 0xf030 +#define S5P_FIMV_DBG_BUFFER_SIZE_V6 0xf034 +#define S5P_FIMV_RET_INSTANCE_ID_V6 0xf070 + +#define S5P_FIMV_ERROR_CODE_V6 0xf074 +#define S5P_FIMV_ERR_WARNINGS_START_V6 160 +#define S5P_FIMV_ERR_DEC_MASK_V6 0xffff +#define S5P_FIMV_ERR_DEC_SHIFT_V6 0 +#define S5P_FIMV_ERR_DSPL_MASK_V6 0xffff0000 +#define S5P_FIMV_ERR_DSPL_SHIFT_V6 16 + +#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE_V6 0xf078 +#define S5P_FIMV_METADATA_STATUS_V6 0xf07C +#define S5P_FIMV_METADATA_ADDR_MB_INFO_V6 0xf080 +#define S5P_FIMV_METADATA_SIZE_MB_INFO_V6 0xf084 + +/* Decoder Registers */ +#define S5P_FIMV_D_CRC_CTRL_V6 0xf0b0 +#define S5P_FIMV_D_DEC_OPTIONS_V6 0xf0b4 +#define S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6 4 +#define S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6 3 +#define S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6 1 +#define S5P_FIMV_D_OPT_LF_CTRL_MASK_V6 0x3 +#define S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6 0 + +#define S5P_FIMV_D_DISPLAY_DELAY_V6 0xf0b8 + +#define S5P_FIMV_D_SET_FRAME_WIDTH_V6 0xf0bc +#define S5P_FIMV_D_SET_FRAME_HEIGHT_V6 0xf0c0 + +#define S5P_FIMV_D_SEI_ENABLE_V6 0xf0c4 + +/* Buffer setting registers */ +#define S5P_FIMV_D_MIN_NUM_DPB_V6 0xf0f0 +#define S5P_FIMV_D_MIN_LUMA_DPB_SIZE_V6 0xf0f4 +#define S5P_FIMV_D_MIN_CHROMA_DPB_SIZE_V6 0xf0f8 +#define S5P_FIMV_D_MVC_NUM_VIEWS_V6 0xf0fc +#define S5P_FIMV_D_MIN_NUM_MV_V6 0xf100 +#define S5P_FIMV_D_NUM_DPB_V6 0xf130 +#define S5P_FIMV_D_LUMA_DPB_SIZE_V6 0xf134 +#define S5P_FIMV_D_CHROMA_DPB_SIZE_V6 0xf138 +#define S5P_FIMV_D_MV_BUFFER_SIZE_V6 0xf13c + +#define S5P_FIMV_D_LUMA_DPB_V6 0xf140 +#define S5P_FIMV_D_CHROMA_DPB_V6 0xf240 +#define S5P_FIMV_D_MV_BUFFER_V6 0xf340 + +#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6 0xf440 +#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6 0xf444 +#define S5P_FIMV_D_METADATA_BUFFER_ADDR_V6 0xf448 +#define S5P_FIMV_D_METADATA_BUFFER_SIZE_V6 0xf44c +#define S5P_FIMV_D_NUM_MV_V6 0xf478 +#define S5P_FIMV_D_CPB_BUFFER_ADDR_V6 0xf4b0 +#define S5P_FIMV_D_CPB_BUFFER_SIZE_V6 0xf4b4 + +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER_V6 0xf4b8 +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6 0xf4bc +#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V6 0xf4c0 +#define S5P_FIMV_D_SLICE_IF_ENABLE_V6 0xf4c4 +#define S5P_FIMV_D_PICTURE_TAG_V6 0xf4c8 +#define S5P_FIMV_D_STREAM_DATA_SIZE_V6 0xf4d0 + +/* Display information register */ +#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6 0xf500 +#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6 0xf504 + +/* Display status */ +#define S5P_FIMV_D_DISPLAY_STATUS_V6 0xf508 + +#define S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6 0xf50c +#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6 0xf510 + +#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6 0xf514 + +#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 0xf518 +#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 0xf51c +#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V6 0xf520 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP_V6 0xf524 +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP_V6 0xf528 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_BOT_V6 0xf52c +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_BOT_V6 0xf530 +#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6 0xf534 +#define S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6 0xf538 + +/* Decoded picture information register */ +#define S5P_FIMV_D_DECODED_FRAME_WIDTH_V6 0xf53c +#define S5P_FIMV_D_DECODED_FRAME_HEIGHT_V6 0xf540 +#define S5P_FIMV_D_DECODED_STATUS_V6 0xf544 +#define S5P_FIMV_DEC_CRC_GEN_MASK_V6 0x1 +#define S5P_FIMV_DEC_CRC_GEN_SHIFT_V6 6 + +#define S5P_FIMV_D_DECODED_LUMA_ADDR_V6 0xf548 +#define S5P_FIMV_D_DECODED_CHROMA_ADDR_V6 0xf54c + +#define S5P_FIMV_D_DECODED_FRAME_TYPE_V6 0xf550 +#define S5P_FIMV_DECODE_FRAME_MASK_V6 7 + +#define S5P_FIMV_D_DECODED_CROP_INFO1_V6 0xf554 +#define S5P_FIMV_D_DECODED_CROP_INFO2_V6 0xf558 +#define S5P_FIMV_D_DECODED_PICTURE_PROFILE_V6 0xf55c +#define S5P_FIMV_D_DECODED_NAL_SIZE_V6 0xf560 +#define S5P_FIMV_D_DECODED_LUMA_CRC_TOP_V6 0xf564 +#define S5P_FIMV_D_DECODED_CHROMA_CRC_TOP_V6 0xf568 +#define S5P_FIMV_D_DECODED_LUMA_CRC_BOT_V6 0xf56c +#define S5P_FIMV_D_DECODED_CHROMA_CRC_BOT_V6 0xf570 + +/* Returned value register for specific setting */ +#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 0xf574 +#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 0xf578 +#define S5P_FIMV_D_RET_PICTURE_TIME_TOP_V6 0xf57c +#define S5P_FIMV_D_RET_PICTURE_TIME_BOT_V6 0xf580 +#define S5P_FIMV_D_CHROMA_FORMAT_V6 0xf588 +#define S5P_FIMV_D_MPEG4_INFO_V6 0xf58c +#define S5P_FIMV_D_H264_INFO_V6 0xf590 + +#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB_V6 0xf594 +#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB_V6 0xf598 +#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM_V6 0xf59c +#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM_V6 0xf5a0 +#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL_V6 0xf5a4 +#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL_V6 0xf5a8 +#define S5P_FIMV_D_METADATA_ADDR_VUI_V6 0xf5ac +#define S5P_FIMV_D_METADATA_SIZE_VUI_V6 0xf5b0 + +#define S5P_FIMV_D_MVC_VIEW_ID_V6 0xf5b4 + +/* SEI related information */ +#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6 0xf5f0 +#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID_V6 0xf5f4 +#define S5P_FIMV_D_FRAME_PACK_SEI_INFO_V6 0xf5f8 +#define S5P_FIMV_D_FRAME_PACK_GRID_POS_V6 0xf5fc + +/* Encoder Registers */ +#define S5P_FIMV_E_FRAME_WIDTH_V6 0xf770 +#define S5P_FIMV_E_FRAME_HEIGHT_V6 0xf774 +#define S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6 0xf778 +#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6 0xf77c +#define S5P_FIMV_E_FRAME_CROP_OFFSET_V6 0xf780 +#define S5P_FIMV_E_ENC_OPTIONS_V6 0xf784 +#define S5P_FIMV_E_PICTURE_PROFILE_V6 0xf788 +#define S5P_FIMV_E_FIXED_PICTURE_QP_V6 0xf790 + +#define S5P_FIMV_E_RC_CONFIG_V6 0xf794 +#define S5P_FIMV_E_RC_QP_BOUND_V6 0xf798 +#define S5P_FIMV_E_RC_RPARAM_V6 0xf79c +#define S5P_FIMV_E_MB_RC_CONFIG_V6 0xf7a0 +#define S5P_FIMV_E_PADDING_CTRL_V6 0xf7a4 +#define S5P_FIMV_E_MV_HOR_RANGE_V6 0xf7ac +#define S5P_FIMV_E_MV_VER_RANGE_V6 0xf7b0 + +#define S5P_FIMV_E_VBV_BUFFER_SIZE_V6 0xf84c +#define S5P_FIMV_E_VBV_INIT_DELAY_V6 0xf850 +#define S5P_FIMV_E_NUM_DPB_V6 0xf890 +#define S5P_FIMV_E_LUMA_DPB_V6 0xf8c0 +#define S5P_FIMV_E_CHROMA_DPB_V6 0xf904 +#define S5P_FIMV_E_ME_BUFFER_V6 0xf948 + +#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6 0xf98c +#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6 0xf990 +#define S5P_FIMV_E_TMV_BUFFER0_V6 0xf994 +#define S5P_FIMV_E_TMV_BUFFER1_V6 0xf998 +#define S5P_FIMV_E_SOURCE_LUMA_ADDR_V6 0xf9f0 +#define S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6 0xf9f4 +#define S5P_FIMV_E_STREAM_BUFFER_ADDR_V6 0xf9f8 +#define S5P_FIMV_E_STREAM_BUFFER_SIZE_V6 0xf9fc +#define S5P_FIMV_E_ROI_BUFFER_ADDR_V6 0xfA00 + +#define S5P_FIMV_E_PARAM_CHANGE_V6 0xfa04 +#define S5P_FIMV_E_IR_SIZE_V6 0xfa08 +#define S5P_FIMV_E_GOP_CONFIG_V6 0xfa0c +#define S5P_FIMV_E_MSLICE_MODE_V6 0xfa10 +#define S5P_FIMV_E_MSLICE_SIZE_MB_V6 0xfa14 +#define S5P_FIMV_E_MSLICE_SIZE_BITS_V6 0xfa18 +#define S5P_FIMV_E_FRAME_INSERTION_V6 0xfa1c + +#define S5P_FIMV_E_RC_FRAME_RATE_V6 0xfa20 +#define S5P_FIMV_E_RC_BIT_RATE_V6 0xfa24 +#define S5P_FIMV_E_RC_QP_OFFSET_V6 0xfa28 +#define S5P_FIMV_E_RC_ROI_CTRL_V6 0xfa2c +#define S5P_FIMV_E_PICTURE_TAG_V6 0xfa30 +#define S5P_FIMV_E_BIT_COUNT_ENABLE_V6 0xfa34 +#define S5P_FIMV_E_MAX_BIT_COUNT_V6 0xfa38 +#define S5P_FIMV_E_MIN_BIT_COUNT_V6 0xfa3c + +#define S5P_FIMV_E_METADATA_BUFFER_ADDR_V6 0xfa40 +#define S5P_FIMV_E_METADATA_BUFFER_SIZE_V6 0xfa44 +#define S5P_FIMV_E_STREAM_SIZE_V6 0xfa80 +#define S5P_FIMV_E_SLICE_TYPE_V6 0xfa84 +#define S5P_FIMV_E_PICTURE_COUNT_V6 0xfa88 +#define S5P_FIMV_E_RET_PICTURE_TAG_V6 0xfa8c +#define S5P_FIMV_E_STREAM_BUFFER_WRITE_POINTER_V6 0xfa90 + +#define S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6 0xfa94 +#define S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6 0xfa98 +#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6 0xfa9c +#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6 0xfaa0 +#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE_V6 0xfaa4 +#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE_V6 0xfaa8 + +#define S5P_FIMV_E_MPEG4_OPTIONS_V6 0xfb10 +#define S5P_FIMV_E_MPEG4_HEC_PERIOD_V6 0xfb14 +#define S5P_FIMV_E_ASPECT_RATIO_V6 0xfb50 +#define S5P_FIMV_E_EXTENDED_SAR_V6 0xfb54 + +#define S5P_FIMV_E_H264_OPTIONS_V6 0xfb58 +#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6 0xfb5c +#define S5P_FIMV_E_H264_LF_BETA_OFFSET_V6 0xfb60 +#define S5P_FIMV_E_H264_I_PERIOD_V6 0xfb64 + +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6 0xfb68 +#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6 0xfb6c +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6 0xfb70 +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6 0xfb74 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 0xfb78 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1_V6 0xfb7c +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2_V6 0xfb80 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3_V6 0xfb84 + +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 0xfb88 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1_V6 0xfb8c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2_V6 0xfb90 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3_V6 0xfb94 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4_V6 0xfb98 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5_V6 0xfb9c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6_V6 0xfba0 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7_V6 0xfba4 + +#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET_V6 0xfba8 +#define S5P_FIMV_E_H264_NUM_T_LAYER_V6 0xfbac + +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 0xfbb0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER1_V6 0xfbb4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER2_V6 0xfbb8 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER3_V6 0xfbbc +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER4_V6 0xfbc0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER5_V6 0xfbc4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER6_V6 0xfbc8 + +#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6 0xfc4c +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE_V6 0 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TOP_BOTTOM_V6 1 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TEMPORAL_V6 2 + +#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1_V6 0xfd40 +#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1_V6 0xfd44 +#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1_V6 0xfd48 +#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1_V6 0xfd4c +#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6 0xfd50 +#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6 0xfd80 + +/* Codec numbers */ +#define S5P_FIMV_CODEC_NONE_V6 -1 + + +#define S5P_FIMV_CODEC_H264_DEC_V6 0 +#define S5P_FIMV_CODEC_H264_MVC_DEC_V6 1 + +#define S5P_FIMV_CODEC_MPEG4_DEC_V6 3 +#define S5P_FIMV_CODEC_FIMV1_DEC_V6 4 +#define S5P_FIMV_CODEC_FIMV2_DEC_V6 5 +#define S5P_FIMV_CODEC_FIMV3_DEC_V6 6 +#define S5P_FIMV_CODEC_FIMV4_DEC_V6 7 +#define S5P_FIMV_CODEC_H263_DEC_V6 8 +#define S5P_FIMV_CODEC_VC1RCV_DEC_V6 9 +#define S5P_FIMV_CODEC_VC1_DEC_V6 10 +/* FIXME: Add 11~12 */ +#define S5P_FIMV_CODEC_MPEG2_DEC_V6 13 +#define S5P_FIMV_CODEC_VP8_DEC_V6 14 +/* FIXME: Add 15~16 */ +#define S5P_FIMV_CODEC_H264_ENC_V6 20 +#define S5P_FIMV_CODEC_H264_MVC_ENC_V6 21 + +#define S5P_FIMV_CODEC_MPEG4_ENC_V6 23 +#define S5P_FIMV_CODEC_H263_ENC_V6 24 + +#define S5P_FIMV_NV12M_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_VALIGN_V6 16 + +#define S5P_FIMV_TMV_BUFFER_ALIGN_V6 16 +#define S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_ME_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6 256 + +#define S5P_FIMV_LUMA_MB_TO_PIXEL_V6 256 +#define S5P_FIMV_CHROMA_MB_TO_PIXEL_V6 128 +#define S5P_FIMV_NUM_TMV_BUFFERS_V6 2 + +#define S5P_FIMV_MAX_FRAME_SIZE_V6 (2 * SZ_1M) +#define S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6 16 +#define S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6 16 + +/* Buffer size requirements defined by hardware */ +#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 1) * 8) +#define S5P_FIMV_ME_BUFFER_SIZE_V6(imw, imh, mbw, mbh) \ + ((DIV_ROUND_UP(imw, 64) * DIV_ROUND_UP(imh, 64) * 256) + \ + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \ + ((w) * ((h) * 64 + 144) + (2048/16 * (h) * 64) + \ + (2048/16 * 256 + 8320)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ + (2096 * ((w) + (h) + 1)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) ((w) * 400) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ + ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ + (((w) * 64) + (((w) + 1) * 16) + (4096 * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(w, h) \ + (((w) * 16) + (((w) + 1) * 16)) + +/* MFC Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V6 (28 * SZ_1K) /* 28KB */ +#define MFC_H264_DEC_CTX_BUF_SIZE_V6 (2 * SZ_1M) /* 2MB */ +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V6 (20 * SZ_1K) /* 20KB */ +#define MFC_H264_ENC_CTX_BUF_SIZE_V6 (100 * SZ_1K) /* 100KB */ +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ + +/* MFCv6 variant defines */ +#define MAX_FW_SIZE_V6 (SZ_1M) /* 1MB */ +#define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ +#define MFC_VERSION_V6 0x61 +#define MFC_NUM_PORTS_V6 1 + +#endif /* _REGS_FIMV_V6_H */ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index a19bece41ba9..9319e93599ae 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -12,6 +12,9 @@ #ifndef _REGS_FIMV_H #define _REGS_FIMV_H +#include <linux/kernel.h> +#include <linux/sizes.h> + #define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) #define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) @@ -144,6 +147,7 @@ #define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 #define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 #define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 +#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3 #define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 #define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 #define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ @@ -213,6 +217,7 @@ #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) +#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4 /* Decode frame address */ #define S5P_FIMV_DECODE_Y_ADR 0x2024 @@ -377,6 +382,16 @@ #define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 #define S5P_FIMV_R2H_CMD_ERR_RET 32 +/* Dummy definition for MFCv6 compatibilty */ +#define S5P_FIMV_CODEC_H264_MVC_DEC -1 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1 +#define S5P_FIMV_MFC_RESET -1 +#define S5P_FIMV_RISC_ON -1 +#define S5P_FIMV_RISC_BASE_ADDRESS -1 +#define S5P_FIMV_CODEC_VP8_DEC -1 +#define S5P_FIMV_REG_CLEAR_BEGIN 0 +#define S5P_FIMV_REG_CLEAR_COUNT 0 + /* Error handling defines */ #define S5P_FIMV_ERR_WARNINGS_START 145 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF @@ -414,5 +429,31 @@ #define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078 #define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C #define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0 +#define S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT 2 + +/* Offset used by the hardware to store addresses */ +#define MFC_OFFSET_SHIFT 11 + +#define FIRMWARE_ALIGN (128 * SZ_1K) /* 128KB */ +#define MFC_H264_CTX_BUF_SIZE (600 * SZ_1K) /* 600KB per H264 instance */ +#define MFC_CTX_BUF_SIZE (10 * SZ_1K) /* 10KB per instance */ +#define DESC_BUF_SIZE (128 * SZ_1K) /* 128KB for DESC buffer */ +#define SHARED_BUF_SIZE (8 * SZ_1K) /* 8KB for shared buffer */ + +#define DEF_CPB_SIZE (256 * SZ_1K) /* 256KB */ +#define MAX_CPB_SIZE (4 * SZ_1M) /* 4MB */ +#define MAX_FW_SIZE (384 * SZ_1K) + +#define MFC_VERSION 0x51 +#define MFC_NUM_PORTS 2 + +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C +#define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170 +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174 +#define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178 + +/* Values for resolution change in display status */ +#define S5P_FIMV_RES_INCREASE 1 +#define S5P_FIMV_RES_DECREASE 2 #endif /* _REGS_FIMV_H */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 5587ef15ca4f..130f4ac8649e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,15 +22,15 @@ #include <media/v4l2-event.h> #include <linux/workqueue.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" +#include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" #define S5P_MFC_NAME "s5p-mfc" #define S5P_MFC_DEC_NAME "s5p-mfc-dec" @@ -149,10 +149,12 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) if (!ctx) continue; ctx->state = MFCINST_ERROR; - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); clear_work_bit(ctx); - wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0); + wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); } clear_bit(0, &dev->hw_lock); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -199,6 +201,7 @@ static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_buf *dst_buf; + struct s5p_mfc_dev *dev = ctx->dev; ctx->state = MFCINST_FINISHED; ctx->sequence++; @@ -213,8 +216,8 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); - if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == - s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) + if (s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_bot, ctx)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; @@ -228,8 +231,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf, *src_buf; - size_t dec_y_addr = s5p_mfc_get_dec_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dec_y_addr; + unsigned int frame_type; + + dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); /* Copy timestamp / timecode from decoded src to dst and set appropraite flags */ @@ -265,10 +271,13 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf; - size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dspl_y_addr; + unsigned int frame_type; unsigned int index; + dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + /* If frame is same as previous then skip and do not dequeue */ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { if (!ctx->after_packed_pb) @@ -285,8 +294,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = ctx->sequence; - if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == - s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) + if (s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_bot, ctx)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = @@ -317,21 +328,23 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, unsigned int index; - dst_frame_status = s5p_mfc_get_dspl_status() + dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; - res_change = s5p_mfc_get_dspl_status() - & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; + res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) + & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK) + >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT; mfc_debug(2, "Frame Status: %x\n", dst_frame_status); if (ctx->state == MFCINST_RES_CHANGE_INIT) ctx->state = MFCINST_RES_CHANGE_FLUSH; - if (res_change) { + if (res_change == S5P_FIMV_RES_INCREASE || + res_change == S5P_FIMV_RES_DECREASE) { ctx->state = MFCINST_RES_CHANGE_INIT; - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } if (ctx->dpb_flush_flag) @@ -365,9 +378,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, && !list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - ctx->consumed_stream += s5p_mfc_get_consumed_stream(); - if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC && - s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME + ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, + get_consumed_stream, dev); + if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC && + s5p_mfc_hw_call(dev->mfc_ops, + get_dec_frame_type, dev) == + S5P_FIMV_DECODE_FRAME_P_FRAME && ctx->consumed_stream + STUFF_BYTE < src_buf->b->v4l2_planes[0].bytesused) { /* Run MFC again on the same buffer */ @@ -379,7 +395,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, ctx->consumed_stream = 0; list_del(&src_buf->list); ctx->src_queue_cnt--; - if (s5p_mfc_err_dec(err) > 0) + if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR); else vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE); @@ -390,12 +406,12 @@ leave_handle_frame: if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) || ctx->dst_queue_cnt < ctx->dpb_count) clear_work_bit(ctx); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Error handling for interrupt */ @@ -412,7 +428,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, dev = ctx->dev; mfc_err("Interrupt Error: %08x\n", err); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); /* Error recovery is dependent on the state of context */ @@ -441,9 +457,11 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, ctx->state = MFCINST_ERROR; /* Mark all dst buffers as having an error */ spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); /* Mark all src buffers as having an error */ - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); spin_unlock_irqrestore(&dev->irqlock, flags); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -461,7 +479,6 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) { struct s5p_mfc_dev *dev; - unsigned int guard_width, guard_height; if (ctx == NULL) return; @@ -470,55 +487,44 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, if (ctx->c_ops->post_seq_start(ctx)) mfc_err("post_seq_start() failed\n"); } else { - ctx->img_width = s5p_mfc_get_img_width(); - ctx->img_height = s5p_mfc_get_img_height(); - - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN); - ctx->buf_height = ALIGN(ctx->img_height, - S5P_FIMV_NV12MT_VALIGN); - mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, " - "buffer dimensions: %dx%d\n", ctx->img_width, - ctx->img_height, ctx->buf_width, - ctx->buf_height); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { - ctx->luma_size = ALIGN(ctx->buf_width * - ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN); - ctx->chroma_size = ALIGN(ctx->buf_width * - ALIGN((ctx->img_height >> 1), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = ALIGN(ctx->buf_width * - ALIGN((ctx->buf_height >> 2), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 24, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN(ctx->img_height + 16, - S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(guard_width * - guard_height, S5P_FIMV_DEC_BUF_ALIGN); - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(guard_width * - guard_height, S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = 0; - } - ctx->dpb_count = s5p_mfc_get_dpb_count(); + ctx->img_width = s5p_mfc_hw_call(dev->mfc_ops, get_img_width, + dev); + ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, + dev); + + s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); + + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, + dev); + ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, + dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else ctx->state = MFCINST_HEAD_PARSED; + + if ((ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) && + !list_empty(&ctx->src_queue)) { + struct s5p_mfc_buf *src_buf; + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); + if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, + dev) < + src_buf->b->v4l2_planes[0].bytesused) + ctx->head_processed = 0; + else + ctx->head_processed = 1; + } else { + ctx->head_processed = 1; + } } - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -533,14 +539,14 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, if (ctx == NULL) return; dev = ctx->dev; - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; clear_work_bit(ctx); if (err == 0) { ctx->state = MFCINST_RUNNING; - if (!ctx->dpb_flush_flag) { + if (!ctx->dpb_flush_flag && ctx->head_processed) { spin_lock_irqsave(&dev->irqlock, flags); if (!list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, @@ -560,7 +566,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -602,7 +608,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Interrupt processing */ @@ -618,81 +624,83 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) atomic_set(&dev->watchdog_cnt, 0); ctx = dev->ctx[dev->curr_ctx]; /* Get the reason of interrupt and the error code */ - reason = s5p_mfc_get_int_reason(); - err = s5p_mfc_get_int_err(); + reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev); + err = s5p_mfc_hw_call(dev->mfc_ops, get_int_err, dev); mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); switch (reason) { - case S5P_FIMV_R2H_CMD_ERR_RET: + case S5P_MFC_R2H_CMD_ERR_RET: /* An error has occured */ if (ctx->state == MFCINST_RUNNING && - s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START) + s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= + dev->warn_start) s5p_mfc_handle_frame(ctx, reason, err); else s5p_mfc_handle_error(ctx, reason, err); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: - case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + case S5P_MFC_R2H_CMD_SLICE_DONE_RET: + case S5P_MFC_R2H_CMD_FIELD_DONE_RET: + case S5P_MFC_R2H_CMD_FRAME_DONE_RET: if (ctx->c_ops->post_frame_start) { if (ctx->c_ops->post_frame_start(ctx)) mfc_err("post_frame_start() failed\n"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); } break; - case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + case S5P_MFC_R2H_CMD_SEQ_DONE_RET: s5p_mfc_handle_seq_done(ctx, reason, err); break; - case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: - ctx->inst_no = s5p_mfc_get_inst_no(); + case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: + ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); ctx->state = MFCINST_GOT_INST; clear_work_bit(ctx); wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: clear_work_bit(ctx); ctx->state = MFCINST_FREE; wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_SYS_INIT_RET: - case S5P_FIMV_R2H_CMD_FW_STATUS_RET: - case S5P_FIMV_R2H_CMD_SLEEP_RET: - case S5P_FIMV_R2H_CMD_WAKEUP_RET: + case S5P_MFC_R2H_CMD_SYS_INIT_RET: + case S5P_MFC_R2H_CMD_FW_STATUS_RET: + case S5P_MFC_R2H_CMD_SLEEP_RET: + case S5P_MFC_R2H_CMD_WAKEUP_RET: if (ctx) clear_work_bit(ctx); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: s5p_mfc_handle_init_buffers(ctx, reason, err); break; - case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET: s5p_mfc_handle_stream_complete(ctx, reason, err); break; default: mfc_debug(2, "Unknown int reason\n"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); } mfc_debug_leave(); return IRQ_HANDLED; irq_cleanup_hw: - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -701,7 +709,7 @@ irq_cleanup_hw: s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); mfc_debug(2, "Exit via irq_cleanup_hw\n"); return IRQ_HANDLED; } @@ -749,6 +757,7 @@ static int s5p_mfc_open(struct file *file) if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { ctx->type = MFCINST_DECODER; ctx->c_ops = get_dec_codec_ops(); + s5p_mfc_dec_init(ctx); /* Setup ctrl handler */ ret = s5p_mfc_dec_ctrls_setup(ctx); if (ret) { @@ -761,6 +770,7 @@ static int s5p_mfc_open(struct file *file) /* only for encoder */ INIT_LIST_HEAD(&ctx->ref_queue); ctx->ref_queue_cnt = 0; + s5p_mfc_enc_init(ctx); /* Setup ctrl handler */ ret = s5p_mfc_enc_ctrls_setup(ctx); if (ret) { @@ -886,19 +896,20 @@ static int s5p_mfc_release(struct file *file) ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); /* Wait until instance is returned or timeout occured */ if (s5p_mfc_wait_for_done_ctx - (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { + (ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { s5p_mfc_clock_off(); mfc_err("Err returning instance\n"); } mfc_debug(2, "After free instance\n"); /* Free resources */ - s5p_mfc_release_codec_buffers(ctx); - s5p_mfc_release_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); if (ctx->type == MFCINST_DECODER) - s5p_mfc_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, + ctx); ctx->inst_no = MFC_NO_INSTANCE_SET; } @@ -910,6 +921,7 @@ static int s5p_mfc_release(struct file *file) mfc_debug(2, "Last instance - release firmware\n"); /* reset <-> F/W release */ s5p_mfc_reset(dev); + s5p_mfc_deinit_hw(dev); s5p_mfc_release_firmware(dev); del_timer_sync(&dev->watchdog_timer); if (s5p_mfc_power_off() < 0) @@ -1041,6 +1053,9 @@ static int s5p_mfc_probe(struct platform_device *pdev) return -ENODEV; } + dev->variant = (struct s5p_mfc_variant *) + platform_get_device_id(pdev)->driver_data; + ret = s5p_mfc_init_pm(dev); if (ret < 0) { dev_err(&pdev->dev, "failed to get mfc clock source\n"); @@ -1076,6 +1091,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) ret = -ENODEV; goto err_res; } + dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", match_child); if (!dev->mem_dev_r) { @@ -1139,6 +1155,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->release = video_device_release, vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); dev->vfd_enc = vfd; ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); @@ -1160,6 +1177,10 @@ static int s5p_mfc_probe(struct platform_device *pdev) dev->watchdog_timer.data = (unsigned long)dev; dev->watchdog_timer.function = s5p_mfc_watchdog; + /* Initialize HW ops and commands based on MFC version */ + s5p_mfc_init_hw_ops(dev); + s5p_mfc_init_hw_cmds(dev); + pr_debug("%s--\n", __func__); return 0; @@ -1280,9 +1301,78 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { NULL) }; +struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { + .h264_ctx = MFC_H264_CTX_BUF_SIZE, + .non_h264_ctx = MFC_CTX_BUF_SIZE, + .dsc = DESC_BUF_SIZE, + .shm = SHARED_BUF_SIZE, +}; + +struct s5p_mfc_buf_size buf_size_v5 = { + .fw = MAX_FW_SIZE, + .cpb = MAX_CPB_SIZE, + .priv = &mfc_buf_size_v5, +}; + +struct s5p_mfc_buf_align mfc_buf_align_v5 = { + .base = MFC_BASE_ALIGN_ORDER, +}; + +static struct s5p_mfc_variant mfc_drvdata_v5 = { + .version = MFC_VERSION, + .port_num = MFC_NUM_PORTS, + .buf_size = &buf_size_v5, + .buf_align = &mfc_buf_align_v5, + .mclk_name = "sclk_mfc", + .fw_name = "s5p-mfc.fw", +}; + +struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V6, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V6, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, +}; + +struct s5p_mfc_buf_size buf_size_v6 = { + .fw = MAX_FW_SIZE_V6, + .cpb = MAX_CPB_SIZE_V6, + .priv = &mfc_buf_size_v6, +}; + +struct s5p_mfc_buf_align mfc_buf_align_v6 = { + .base = 0, +}; + +static struct s5p_mfc_variant mfc_drvdata_v6 = { + .version = MFC_VERSION_V6, + .port_num = MFC_NUM_PORTS_V6, + .buf_size = &buf_size_v6, + .buf_align = &mfc_buf_align_v6, + .mclk_name = "aclk_333", + .fw_name = "s5p-mfc-v6.fw", +}; + +static struct platform_device_id mfc_driver_ids[] = { + { + .name = "s5p-mfc", + .driver_data = (unsigned long)&mfc_drvdata_v5, + }, { + .name = "s5p-mfc-v5", + .driver_data = (unsigned long)&mfc_drvdata_v5, + }, { + .name = "s5p-mfc-v6", + .driver_data = (unsigned long)&mfc_drvdata_v6, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, mfc_driver_ids); + static struct platform_driver s5p_mfc_driver = { - .probe = s5p_mfc_probe, - .remove = __devexit_p(s5p_mfc_remove), + .probe = s5p_mfc_probe, + .remove = __devexit_p(s5p_mfc_remove), + .id_table = mfc_driver_ids, .driver = { .name = S5P_MFC_NAME, .owner = THIS_MODULE, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c index 91a415573bd2..f0a41c95df84 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c @@ -1,7 +1,7 @@ /* * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -10,111 +10,20 @@ * (at your option) any later version. */ -#include "regs-mfc.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd_v6.h" -/* This function is used to send a command to the MFC */ -static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) -{ - int cur_cmd; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while waiting for hardware\n"); - return -EIO; - } - cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); - } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); - mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); - mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); - mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); - mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); - /* Issue the command */ - mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); - return 0; -} - -/* Initialize the MFC */ -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = dev->fw_size; - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); -} - -/* Suspend the MFC hardware */ -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); -} +static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; -/* Wake up the MFC hardware */ -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) { - struct s5p_mfc_cmd_args h2r_args; + if (IS_MFCV6(dev)) + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); + else + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); + dev->mfc_cmds = s5p_mfc_cmds; } - - -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - /* Preparing decoding - getting instance number */ - mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->codec_mode; - h2r_args.arg[1] = 0; /* no crc & no pixelcache */ - h2r_args.arg[2] = ctx->ctx_ofs; - h2r_args.arg[3] = ctx->ctx_size; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to create a new instance\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - if (ctx->state == MFCINST_FREE) { - mfc_err("Instance already returned\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - /* Closing decoding instance */ - mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->inst_no; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to return an instance\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - return 0; -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h index 8b090d3723e7..282e6c780702 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h @@ -1,7 +1,7 @@ /* * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -21,10 +21,15 @@ struct s5p_mfc_cmd_args { unsigned int arg[MAX_H2R_ARG]; }; -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); +struct s5p_mfc_hw_cmds { + int (*cmd_host2risc)(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args); + int (*sys_init_cmd)(struct s5p_mfc_dev *dev); + int (*sleep_cmd)(struct s5p_mfc_dev *dev); + int (*wakeup_cmd)(struct s5p_mfc_dev *dev); + int (*open_inst_cmd)(struct s5p_mfc_ctx *ctx); + int (*close_inst_cmd)(struct s5p_mfc_ctx *ctx); +}; +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev); #endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c new file mode 100644 index 000000000000..138778083c63 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -0,0 +1,166 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "regs-mfc.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" + +/* This function is used to send a command to the MFC */ +int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + int cur_cmd; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while waiting for hardware\n"); + return -EIO; + } + cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); + } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); + mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); + mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); + mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); + mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); + return 0; +} + +/* Initialize the MFC */ +int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = dev->fw_size; + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, + &h2r_args); +} + +/* Suspend the MFC hardware */ +int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); +} + +/* Wake up the MFC hardware */ +int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP, + &h2r_args); +} + + +int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + /* Preparing decoding - getting instance number */ + mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC; + break; + case S5P_MFC_CODEC_VC1_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC; + break; + case S5P_MFC_CODEC_H263_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC; + break; + case S5P_MFC_CODEC_H264_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC; + break; + case S5P_MFC_CODEC_H263_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC; + break; + default: + h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; + }; + h2r_args.arg[1] = 0; /* no crc & no pixelcache */ + h2r_args.arg[2] = ctx->ctx.ofs; + h2r_args.arg[3] = ctx->ctx.size; + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to create a new instance\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + if (ctx->state == MFCINST_FREE) { + mfc_err("Instance already returned\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + /* Closing decoding instance */ + mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = ctx->inst_no; + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to return an instance\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + return 0; +} + +/* Initialize cmd function pointers for MFC v5 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, + .sleep_cmd = s5p_mfc_sleep_cmd_v5, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v5, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v5, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) +{ + return &s5p_mfc_cmds_v5; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h new file mode 100644 index 000000000000..6928a5514c1b --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h @@ -0,0 +1,20 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_V5_H_ +#define S5P_MFC_CMD_V5_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c new file mode 100644 index 000000000000..754bfbcb1c43 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -0,0 +1,156 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "s5p_mfc_common.h" + +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" + +int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + mfc_debug(2, "Issue the command: %d\n", cmd); + + /* Reset RISC2HOST command */ + mfc_write(dev, 0x0, S5P_FIMV_RISC2HOST_CMD_V6); + + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0x1, S5P_FIMV_HOST2RISC_INT_V6); + + return 0; +} + +int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); + mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, + &h2r_args); +} + +int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, + &h2r_args); +} + +int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, + &h2r_args); +} + +/* Open a new instance and get its number */ +int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int codec_type; + + mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + codec_type = S5P_FIMV_CODEC_H264_DEC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_DEC: + codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; + break; + case S5P_MFC_CODEC_VC1_DEC: + codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; + break; + case S5P_MFC_CODEC_H263_DEC: + codec_type = S5P_FIMV_CODEC_H263_DEC_V6; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; + break; + case S5P_MFC_CODEC_VP8_DEC: + codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; + break; + case S5P_MFC_CODEC_H264_ENC: + codec_type = S5P_FIMV_CODEC_H264_ENC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_ENC: + codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; + break; + case S5P_MFC_CODEC_H263_ENC: + codec_type = S5P_FIMV_CODEC_H263_ENC_V6; + break; + default: + codec_type = S5P_FIMV_CODEC_NONE_V6; + }; + mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); + mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ + + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, + &h2r_args); +} + +/* Close instance */ +int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret = 0; + + dev->curr_ctx = ctx->num; + if (ctx->state != MFCINST_FREE) { + mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + ret = s5p_mfc_cmd_host2risc_v6(dev, + S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, + &h2r_args); + } else { + ret = -EINVAL; + } + + return ret; +} + +/* Initialize cmd function pointers for MFC v6 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, + .sleep_cmd = s5p_mfc_sleep_cmd_v6, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v6, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) +{ + return &s5p_mfc_cmds_v6; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h new file mode 100644 index 000000000000..b7a8e57837b5 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h @@ -0,0 +1,20 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_V6_H_ +#define S5P_MFC_CMD_V6_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 519b0d66d8d1..f02e0497ca98 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -16,13 +16,14 @@ #ifndef S5P_MFC_COMMON_H_ #define S5P_MFC_COMMON_H_ -#include "regs-mfc.h" #include <linux/platform_device.h> #include <linux/videodev2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-core.h> +#include "regs-mfc.h" +#include "regs-mfc-v6.h" /* Definitions related to MFC memory */ @@ -30,17 +31,6 @@ * while mmaping */ #define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) -/* Offset used by the hardware to store addresses */ -#define MFC_OFFSET_SHIFT 11 - -#define FIRMWARE_ALIGN 0x20000 /* 128KB */ -#define MFC_H264_CTX_BUF_SIZE 0x96000 /* 600KB per H264 instance */ -#define MFC_CTX_BUF_SIZE 0x2800 /* 10KB per instance */ -#define DESC_BUF_SIZE 0x20000 /* 128KB for DESC buffer */ -#define SHARED_BUF_SIZE 0x2000 /* 8KB for shared buffer */ - -#define DEF_CPB_SIZE 0x40000 /* 512KB */ - #define MFC_BANK1_ALLOC_CTX 0 #define MFC_BANK2_ALLOC_CTX 1 @@ -74,7 +64,40 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 64 +#define MFC_MAX_CTRLS 70 + +#define S5P_MFC_CODEC_NONE -1 +#define S5P_MFC_CODEC_H264_DEC 0 +#define S5P_MFC_CODEC_H264_MVC_DEC 1 +#define S5P_MFC_CODEC_VC1_DEC 2 +#define S5P_MFC_CODEC_MPEG4_DEC 3 +#define S5P_MFC_CODEC_MPEG2_DEC 4 +#define S5P_MFC_CODEC_H263_DEC 5 +#define S5P_MFC_CODEC_VC1RCV_DEC 6 +#define S5P_MFC_CODEC_VP8_DEC 7 + +#define S5P_MFC_CODEC_H264_ENC 20 +#define S5P_MFC_CODEC_H264_MVC_ENC 21 +#define S5P_MFC_CODEC_MPEG4_ENC 22 +#define S5P_MFC_CODEC_H263_ENC 23 + +#define S5P_MFC_R2H_CMD_EMPTY 0 +#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 +#define S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET 2 +#define S5P_MFC_R2H_CMD_SEQ_DONE_RET 3 +#define S5P_MFC_R2H_CMD_INIT_BUFFERS_RET 4 +#define S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET 6 +#define S5P_MFC_R2H_CMD_SLEEP_RET 7 +#define S5P_MFC_R2H_CMD_WAKEUP_RET 8 +#define S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET 9 +#define S5P_MFC_R2H_CMD_DPB_FLUSH_RET 10 +#define S5P_MFC_R2H_CMD_NAL_ABORT_RET 11 +#define S5P_MFC_R2H_CMD_FW_STATUS_RET 12 +#define S5P_MFC_R2H_CMD_FRAME_DONE_RET 13 +#define S5P_MFC_R2H_CMD_FIELD_DONE_RET 14 +#define S5P_MFC_R2H_CMD_SLICE_DONE_RET 15 +#define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 +#define S5P_MFC_R2H_CMD_ERR_RET 32 #define mfc_read(dev, offset) readl(dev->regs_base + (offset)) #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ @@ -177,6 +200,58 @@ struct s5p_mfc_pm { struct device *device; }; +struct s5p_mfc_buf_size_v5 { + unsigned int h264_ctx; + unsigned int non_h264_ctx; + unsigned int dsc; + unsigned int shm; +}; + +struct s5p_mfc_buf_size_v6 { + unsigned int dev_ctx; + unsigned int h264_dec_ctx; + unsigned int other_dec_ctx; + unsigned int h264_enc_ctx; + unsigned int other_enc_ctx; +}; + +struct s5p_mfc_buf_size { + unsigned int fw; + unsigned int cpb; + void *priv; +}; + +struct s5p_mfc_buf_align { + unsigned int base; +}; + +struct s5p_mfc_variant { + unsigned int version; + unsigned int port_num; + struct s5p_mfc_buf_size *buf_size; + struct s5p_mfc_buf_align *buf_align; + char *mclk_name; + char *fw_name; +}; + +/** + * struct s5p_mfc_priv_buf - represents internal used buffer + * @alloc: allocation-specific context for each buffer + * (videobuf2 allocator) + * @ofs: offset of each buffer, will be used for MFC + * @virt: kernel virtual address, only valid when the + * buffer accessed by driver + * @dma: DMA address, only valid when kernel DMA API used + * @size: size of the buffer + */ +struct s5p_mfc_priv_buf { + void *alloc; + unsigned long ofs; + void *virt; + dma_addr_t dma; + size_t size; +}; + /** * struct s5p_mfc_dev - The struct containing driver internal parameters. * @@ -191,6 +266,7 @@ struct s5p_mfc_pm { * @dec_ctrl_handler: control framework handler for decoding * @enc_ctrl_handler: control framework handler for encoding * @pm: power management control + * @variant: MFC hardware variant information * @num_inst: couter of active MFC instances * @irqlock: lock for operations on videobuf2 queues * @condlock: lock for changing/checking if a context is ready to be @@ -212,6 +288,10 @@ struct s5p_mfc_pm { * @watchdog_work: worker for the watchdog * @alloc_ctx: videobuf2 allocator contexts for two memory banks * @enter_suspend: flag set when entering suspend + * @ctx_buf: common context memory (MFCv6) + * @warn_start: hardware error code from which warnings start + * @mfc_ops: ops structure holding HW operation function pointers + * @mfc_cmds: cmd structure holding HW commands function pointers * */ struct s5p_mfc_dev { @@ -226,6 +306,7 @@ struct s5p_mfc_dev { struct v4l2_ctrl_handler dec_ctrl_handler; struct v4l2_ctrl_handler enc_ctrl_handler; struct s5p_mfc_pm pm; + struct s5p_mfc_variant *variant; int num_inst; spinlock_t irqlock; /* lock when operating on videobuf2 queues */ spinlock_t condlock; /* lock when changing/checking if a context is @@ -248,6 +329,11 @@ struct s5p_mfc_dev { struct work_struct watchdog_work; void *alloc_ctx[2]; unsigned long enter_suspend; + + struct s5p_mfc_priv_buf ctx_buf; + int warn_start; + struct s5p_mfc_hw_ops *mfc_ops; + struct s5p_mfc_hw_cmds *mfc_cmds; }; /** @@ -262,7 +348,6 @@ struct s5p_mfc_h264_enc_params { u8 max_ref_pic; u8 num_ref_pic_4p; int _8x8_transform; - int rc_mb; int rc_mb_dark; int rc_mb_smooth; int rc_mb_static; @@ -281,6 +366,23 @@ struct s5p_mfc_h264_enc_params { enum v4l2_mpeg_video_h264_level level_v4l2; int level; u16 cpb_size; + int interlace; + u8 hier_qp; + u8 hier_qp_type; + u8 hier_qp_layer; + u8 hier_qp_layer_qp[7]; + u8 sei_frame_packing; + u8 sei_fp_curr_frame_0; + u8 sei_fp_arrangement_type; + + u8 fmo; + u8 fmo_map_type; + u8 fmo_slice_grp; + u8 fmo_chg_dir; + u32 fmo_chg_rate; + u32 fmo_run_len[4]; + u8 aso; + u32 aso_slice_order[8]; }; /** @@ -319,9 +421,11 @@ struct s5p_mfc_enc_params { u8 pad_cb; u8 pad_cr; int rc_frame; + int rc_mb; u32 rc_bitrate; u16 rc_reaction_coeff; u16 vbv_size; + u32 vbv_delay; enum v4l2_mpeg_video_header_mode seq_hdr_mode; enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; @@ -330,7 +434,6 @@ struct s5p_mfc_enc_params { u8 num_b_frame; u32 rc_framerate_num; u32 rc_framerate_denom; - int interlace; union { struct s5p_mfc_h264_enc_params h264; @@ -388,6 +491,8 @@ struct s5p_mfc_codec_ops { * decoding buffer * @dpb_flush_flag: flag used to indicate that a DPB buffers are being * flushed + * @head_processed: flag mentioning whether the header data is processed + * completely or not * @bank1_buf: handle to memory allocated for temporary buffers from * memory bank 1 * @bank1_phys: address of the temporary buffers from memory bank 1 @@ -412,19 +517,20 @@ struct s5p_mfc_codec_ops { * @display_delay_enable: display delay for H264 enable flag * @after_packed_pb: flag used to track buffer when stream is in * Packed PB format + * @sei_fp_parse: enable/disable parsing of frame packing SEI information * @dpb_count: count of the DPB buffers required by MFC hw * @total_dpb_count: count of DPB buffers with additional buffers * requested by the application - * @ctx_buf: handle to the memory associated with this context - * @ctx_phys: address of the memory associated with this context - * @ctx_size: size of the memory associated with this context - * @desc_buf: description buffer for decoding handle - * @desc_phys: description buffer for decoding address - * @shm_alloc: handle for the shared memory buffer - * @shm: virtual address for the shared memory buffer - * @shm_ofs: address offset for shared memory + * @ctx: context buffer information + * @dsc: descriptor buffer information + * @shm: shared memory buffer information + * @mv_count: number of MV buffers allocated for decoding * @enc_params: encoding parameters for MFC * @enc_dst_buf_size: size of the buffers for encoder output + * @luma_dpb_size: dpb buffer size for luma + * @chroma_dpb_size: dpb buffer size for chroma + * @me_buffer_size: size of the motion estimation buffer + * @tmv_buffer_size: size of temporal predictor motion vector buffer * @frame_type: used to force the type of the next encoded frame * @ref_queue: list of the reference buffers for encoding * @ref_queue_cnt: number of the buffers in the reference list @@ -473,6 +579,7 @@ struct s5p_mfc_ctx { unsigned long consumed_stream; unsigned int dpb_flush_flag; + unsigned int head_processed; /* Buffers */ void *bank1_buf; @@ -502,37 +609,41 @@ struct s5p_mfc_ctx { int display_delay; int display_delay_enable; int after_packed_pb; + int sei_fp_parse; int dpb_count; int total_dpb_count; - + int mv_count; /* Buffers */ - void *ctx_buf; - size_t ctx_phys; - size_t ctx_ofs; - size_t ctx_size; - - void *desc_buf; - size_t desc_phys; - - - void *shm_alloc; - void *shm; - size_t shm_ofs; + struct s5p_mfc_priv_buf ctx; + struct s5p_mfc_priv_buf dsc; + struct s5p_mfc_priv_buf shm; struct s5p_mfc_enc_params enc_params; size_t enc_dst_buf_size; + size_t luma_dpb_size; + size_t chroma_dpb_size; + size_t me_buffer_size; + size_t tmv_buffer_size; enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; struct list_head ref_queue; unsigned int ref_queue_cnt; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + union { + unsigned int mb; + unsigned int bits; + } slice_size; + struct s5p_mfc_codec_ops *c_ops; struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; struct v4l2_ctrl_handler ctrl_handler; + unsigned int frame_tag; + size_t scratch_buf_size; }; /* @@ -565,6 +676,9 @@ struct mfc_control { __u8 is_volatile; }; +/* Macro for making hardware specific calls */ +#define s5p_mfc_hw_call(f, op, args...) \ + ((f && f->op) ? f->op(args) : -ENODEV) #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) #define ctrl_to_ctx(__ctrl) \ @@ -575,4 +689,9 @@ void set_work_bit(struct s5p_mfc_ctx *ctx); void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); +#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ + (dev->variant->port_num ? 1 : 0) : 0) : 0) +#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) +#define IS_MFCV6(dev) (dev->variant->version >= 0x60 ? 1 : 0) + #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 0deba6bc687c..585b7b0ed8ec 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -15,11 +15,11 @@ #include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/sched.h> -#include "regs-mfc.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" static void *s5p_mfc_bitproc_buf; @@ -37,13 +37,19 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); + err = request_firmware((const struct firmware **)&fw_blob, - "s5p-mfc.fw", dev->v4l2_dev.dev); + dev->variant->fw_name, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; } - dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN); + dev->fw_size = dev->variant->buf_size->fw; + if (fw_blob->size > dev->fw_size) { + mfc_err("MFC firmware is too big to be loaded\n"); + release_firmware(fw_blob); + return -ENOMEM; + } if (s5p_mfc_bitproc_buf) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); release_firmware(fw_blob); @@ -77,32 +83,37 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) return -EIO; } dev->bank1 = s5p_mfc_bitproc_phys; - b_base = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BASE_ALIGN_ORDER); - if (IS_ERR(b_base)) { - vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); - s5p_mfc_bitproc_phys = 0; - s5p_mfc_bitproc_buf = NULL; - mfc_err("Allocating bank2 base failed\n"); - release_firmware(fw_blob); - return -ENOMEM; - } - bank2_base_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); - vb2_dma_contig_memops.put(b_base); - if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { - mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); - vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); - s5p_mfc_bitproc_phys = 0; - s5p_mfc_bitproc_buf = NULL; - release_firmware(fw_blob); - return -EIO; + if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { + b_base = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], + 1 << MFC_BASE_ALIGN_ORDER); + if (IS_ERR(b_base)) { + vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); + s5p_mfc_bitproc_phys = 0; + s5p_mfc_bitproc_buf = NULL; + mfc_err("Allocating bank2 base failed\n"); + release_firmware(fw_blob); + return -ENOMEM; + } + bank2_base_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); + vb2_dma_contig_memops.put(b_base); + if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { + mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); + vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); + s5p_mfc_bitproc_phys = 0; + s5p_mfc_bitproc_buf = NULL; + release_firmware(fw_blob); + return -EIO; + } + /* Valid buffers passed to MFC encoder with LAST_FRAME command + * should not have address of bank2 - MFC will treat it as a null frame. + * To avoid such situation we set bank2 address below the pool address. + */ + dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); + } else { + dev->bank2 = dev->bank1; } - /* Valid buffers passed to MFC encoder with LAST_FRAME command - * should not have address of bank2 - MFC will treat it as a null frame. - * To avoid such situation we set bank2 address below the pool address. - */ - dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); wmb(); release_firmware(fw_blob); @@ -119,8 +130,9 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); + err = request_firmware((const struct firmware **)&fw_blob, - "s5p-mfc.fw", dev->v4l2_dev.dev); + dev->variant->fw_name, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; @@ -161,46 +173,81 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) { unsigned int mc_status; unsigned long timeout; + int i; mfc_debug_enter(); - /* Stop procedure */ - /* reset RISC */ - mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); - /* All reset except for MC */ - mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); - mdelay(10); - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* Check MC status */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while resetting MFC\n"); - return -EIO; - } - mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + if (IS_MFCV6(dev)) { + /* Reset IP */ + /* except RISC, reset */ + mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6); + /* reset release */ + mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6); + + /* Zero Initialization of MFC registers */ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); + + for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) + mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); - } while (mc_status & 0x3); + /* Reset */ + mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); + mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); + mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); + } else { + /* Stop procedure */ + /* reset RISC */ + mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); + /* All reset except for MC */ + mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); + mdelay(10); + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* Check MC status */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while resetting MFC\n"); + return -EIO; + } + + mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + + } while (mc_status & 0x3); + + mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); + mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); + } - mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); - mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); mfc_debug_leave(); return 0; } static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { - mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); - mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); - mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2); + if (IS_MFCV6(dev)) { + mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); + mfc_debug(2, "Base Address : %08x\n", dev->bank1); + } else { + mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); + mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); + mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", + dev->bank1, dev->bank2); + } } static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) { - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); - mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); - mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + if (IS_MFCV6(dev)) { + /* Zero initialization should be done before RESET. + * Nothing to do here. */ + } else { + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + } } /* Initialize hardware */ @@ -228,9 +275,12 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); /* 3. Release reset signal to the RISC */ s5p_mfc_clean_dev_int_flags(dev); - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + if (IS_MFCV6(dev)) + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -238,7 +288,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ - ret = s5p_mfc_sys_init_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); s5p_mfc_reset(dev); @@ -246,7 +296,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) return ret; } mfc_debug(2, "Ok, now will write a command to init the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -254,7 +304,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SYS_INIT_RET) { + S5P_MFC_R2H_CMD_SYS_INIT_RET) { /* Failure. */ mfc_err("Failed to init firmware - error: %d int: %d\n", dev->int_err, dev->int_type); @@ -262,7 +312,11 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clock_off(); return -EIO; } - ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + if (IS_MFCV6(dev)) + ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); + else + ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); s5p_mfc_clock_off(); @@ -271,6 +325,17 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } +/* Deinitialize hardware */ +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) +{ + s5p_mfc_clock_on(); + + s5p_mfc_reset(dev); + s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); + + s5p_mfc_clock_off(); +} + int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { int ret; @@ -278,19 +343,19 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) mfc_debug_enter(); s5p_mfc_clock_on(); s5p_mfc_clean_dev_int_flags(dev); - ret = s5p_mfc_sleep_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; } - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) { mfc_err("Failed to sleep\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SLEEP_RET) { + S5P_MFC_R2H_CMD_SLEEP_RET) { /* Failure. */ mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, dev->int_type); @@ -320,22 +385,25 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Initialize firmware */ - ret = s5p_mfc_wakeup_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; } /* 4. Release reset signal to the RISC */ - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + if (IS_MFCV6(dev)) + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to load firmware\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_WAKEUP_RET) { + S5P_MFC_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, dev->int_type); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h index e1e0c544b6a2..90aa9b9886d5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h @@ -20,6 +20,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev); int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev); int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); int s5p_mfc_sleep(struct s5p_mfc_dev *dev); int s5p_mfc_wakeup(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 6ee21bb71398..eb6a70b0f821 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -23,85 +23,114 @@ #include <linux/workqueue.h> #include <media/v4l2-ctrls.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" + +#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264 +#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT_16X16 static struct s5p_mfc_fmt formats[] = { { + .name = "4:2:0 2 Planes 16x16 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_FIMV_CODEC_NONE, + .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - }, + }, { - .name = "4:2:0 2 Planes", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_FIMV_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_FIMV_CODEC_H264_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "H263 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_FIMV_CODEC_H263_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H264/MVC Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264_MVC, + .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG1 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG1, - .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H263 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG2 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG2, - .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG1 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG1, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG2 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG2, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "XviD Encoded Stream", - .fourcc = V4L2_PIX_FMT_XVID, - .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "VC1 Encoded Stream", - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, - .codec_mode = S5P_FIMV_CODEC_VC1_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "XviD Encoded Stream", + .fourcc = V4L2_PIX_FMT_XVID, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "VC1 RCV Encoded Stream", - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, - .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "VC1 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, + .codec_mode = S5P_MFC_CODEC_VC1_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + }, + { + .name = "VC1 RCV Encoded Stream", + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, + .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + }, + { + .name = "VP8 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = S5P_MFC_CODEC_VP8_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, }; @@ -297,7 +326,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) /* If the MFC is parsing the header, * so wait until it is finished */ s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET, + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && @@ -342,21 +371,36 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) /* Try format */ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; - if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - mfc_err("This node supports decoding only\n"); - return -EINVAL; - } - fmt = find_format(f, MFC_FMT_DEC); - if (!fmt) { - mfc_err("Unsupported format\n"); - return -EINVAL; - } - if (fmt->type != MFC_FMT_DEC) { - mfc_err("\n"); - return -EINVAL; + mfc_debug(2, "Type is %d\n", f->type); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = find_format(f, MFC_FMT_DEC); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for destination.\n"); + return -EINVAL; + } + if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (!IS_MFCV6(dev) && + (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } } + return 0; } @@ -379,8 +423,29 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) ret = -EBUSY; goto out; } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + ctx->dst_fmt = fmt; + mfc_debug_leave(); + return ret; + } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_err("Wrong type error for S_FMT : %d", f->type); + return -EINVAL; + } fmt = find_format(f, MFC_FMT_DEC); - if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { + if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { mfc_err("Unknown codec\n"); ret = -EINVAL; goto out; @@ -391,6 +456,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) ret = -EINVAL; goto out; } + if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } ctx->src_fmt = fmt; ctx->codec_mode = fmt->codec_mode; mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); @@ -476,7 +545,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, return -ENOMEM; } ctx->total_dpb_count = reqbufs->count; - ret = s5p_mfc_alloc_codec_buffers(ctx); + ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx); if (ret) { mfc_err("Failed to allocate decoding buffers\n"); reqbufs->count = 0; @@ -492,15 +561,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, reqbufs->count = 0; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - s5p_mfc_release_codec_buffers(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, + ctx); s5p_mfc_clock_off(); return -ENOMEM; } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); + S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); } return ret; } @@ -582,18 +652,22 @@ static int vidioc_streamon(struct file *file, void *priv, ctx->src_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; ctx->output_state = QUEUE_FREE; - s5p_mfc_alloc_instance_buffer(ctx); - s5p_mfc_alloc_dec_temp_buffers(ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, + ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_dec_temp_buffers, + ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) { + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); - s5p_mfc_release_instance_buffer(ctx); - s5p_mfc_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, + release_instance_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, + release_dec_desc_buffer, ctx); return -EIO; } mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); @@ -662,7 +736,7 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) /* Should wait for the header to be parsed */ s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0); + S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); if (ctx->state >= MFCINST_HEAD_PARSED && ctx->state < MFCINST_ABORT) { ctrl->val = ctx->dpb_count; @@ -686,6 +760,7 @@ static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *cr) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; u32 left, right, top, bottom; if (ctx->state != MFCINST_HEAD_PARSED && @@ -695,10 +770,10 @@ static int vidioc_g_crop(struct file *file, void *priv, return -EINVAL; } if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { - left = s5p_mfc_read_shm(ctx, CROP_INFO_H); + left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; - top = s5p_mfc_read_shm(ctx, CROP_INFO_V); + top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx); bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; cr->c.left = left; @@ -749,6 +824,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; /* Video output for decoding (source) * this can be set after getting an instance */ @@ -784,7 +860,13 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; - allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + + if (IS_MFCV6(dev)) + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + else + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state == MFCINST_INIT) { @@ -876,7 +958,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -892,19 +974,21 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0); + S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); aborted = 1; } spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; ctx->dpb_flush_flag = 1; ctx->dec_dst_flag = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -944,7 +1028,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_dec_qops = { @@ -1028,3 +1112,13 @@ void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) ctx->ctrls[i] = NULL; } +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_DEC; + ctx->src_fmt = find_format(&f, MFC_FMT_DEC); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_DEC; + ctx->dst_fmt = find_format(&f, MFC_FMT_RAW); + mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n", + (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt); +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h index fdf1d99a9d15..d06a7cab5eb1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h @@ -19,5 +19,6 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_dec_def_fmt(bool src); int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx); #endif /* S5P_MFC_DEC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 179e4db60b15..2af6d522f4ac 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -25,48 +25,64 @@ #include <linux/workqueue.h> #include <media/v4l2-ctrls.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" +#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12MT +#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 + static struct s5p_mfc_fmt formats[] = { { - .name = "4:2:0 2 Planes 64x32 Tiles", - .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_FIMV_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes 16x16 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes 64x32 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "4:2:0 2 Planes", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_FIMV_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_FIMV_CODEC_H264_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, { - .name = "H263 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_FIMV_CODEC_H263_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "H263 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, }; @@ -574,7 +590,8 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode a frame */ - if (ctx->state == MFCINST_RUNNING && + if ((ctx->state == MFCINST_RUNNING || + ctx->state == MFCINST_HEAD_PARSED) && ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode remaining frames */ @@ -619,7 +636,8 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; } @@ -638,14 +656,23 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) list_del(&dst_mb->list); ctx->dst_queue_cnt--; vb2_set_plane_payload(dst_mb->b, 0, - s5p_mfc_get_enc_strm_size()); + s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev)); vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); spin_unlock_irqrestore(&dev->irqlock, flags); } - ctx->state = MFCINST_RUNNING; - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + if (IS_MFCV6(dev)) { + ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */ + } else { + ctx->state = MFCINST_RUNNING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } + + if (IS_MFCV6(dev)) + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, + get_enc_dpb_count, dev); + return 0; } @@ -662,14 +689,16 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr, + src_c_addr); spin_unlock_irqrestore(&dev->irqlock, flags); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; @@ -685,15 +714,16 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) unsigned int strm_size; unsigned long flags; - slice_type = s5p_mfc_get_enc_slice_type(); - strm_size = s5p_mfc_get_enc_strm_size(); + slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); + strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); mfc_debug(2, "Encoded slice type: %d", slice_type); mfc_debug(2, "Encoded stream size: %d", strm_size); mfc_debug(2, "Display order: %d", mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); spin_lock_irqsave(&dev->irqlock, flags); if (slice_type >= 0) { - s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr); + s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, + &enc_y_addr, &enc_c_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); @@ -939,15 +969,16 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_fmt_mp->plane_fmt[0].bytesperline = 0; ctx->dst_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; - s5p_mfc_alloc_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, \ - S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) { + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 1)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); - s5p_mfc_release_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, + ctx); ret = -EIO; goto out; } @@ -958,6 +989,17 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_err("failed to set output format\n"); return -EINVAL; } + + if (!IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + if (fmt->num_planes != pix_fmt_mp->num_planes) { mfc_err("failed to set output format\n"); ret = -EINVAL; @@ -970,45 +1012,13 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n", pix_fmt_mp->width, pix_fmt_mp->height, ctx->img_width, ctx->img_height); - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN); - ctx->luma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height, - S5P_FIMV_NV12M_LVALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height - >> 1), S5P_FIMV_NV12M_CVALIGN); - - ctx->luma_size = ALIGN(ctx->luma_size, - S5P_FIMV_NV12M_SALIGN); - ctx->chroma_size = ALIGN(ctx->chroma_size, - S5P_FIMV_NV12M_SALIGN); - - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - - } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN); - ctx->luma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height - >> 1), S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(ctx->luma_size, - S5P_FIMV_NV12MT_SALIGN); - ctx->chroma_size = ALIGN(ctx->chroma_size, - S5P_FIMV_NV12MT_SALIGN); - - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - } + + s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); + pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + ctx->src_bufs_cnt = 0; ctx->output_state = QUEUE_FREE; } else { @@ -1023,6 +1033,7 @@ out: static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; @@ -1042,12 +1053,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, return ret; } ctx->capture_state = QUEUE_BUFS_REQUESTED; - ret = s5p_mfc_alloc_codec_buffers(ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers\n"); - reqbufs->count = 0; - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - return -ENOMEM; + + if (!IS_MFCV6(dev)) { + ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, + alloc_codec_buffers, ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers\n"); + reqbufs->count = 0; + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; + } } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->output_state != QUEUE_FREE) { @@ -1310,6 +1325,13 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->codec.h264.profile = S5P_FIMV_ENC_PROFILE_H264_BASELINE; break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + if (IS_MFCV6(dev)) + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE; + else + ret = -EINVAL; + break; default: ret = -EINVAL; } @@ -1349,7 +1371,7 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->codec.h264._8x8_transform = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - p->codec.h264.rc_mb = ctrl->val; + p->rc_mb = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: p->codec.h264.rc_frame_qp = ctrl->val; @@ -1500,7 +1522,7 @@ int vidioc_encoder_cmd(struct file *file, void *priv, mfc_debug(2, "EOS: empty src queue, entering finishing state"); ctx->state = MFCINST_FINISHING; spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { mfc_debug(2, "EOS: marking last buffer of stream"); buf = list_entry(ctx->src_queue.prev, @@ -1583,6 +1605,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; if (ctx->state != MFCINST_GOT_INST) { mfc_err("inavlid state: %d\n", ctx->state); @@ -1611,8 +1634,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, *buf_count = MFC_MAX_BUFFERS; psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; - allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; - allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + if (IS_MFCV6(dev)) { + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + allocators[1] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + } else { + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + allocators[1] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + } } else { mfc_err("inavlid queue type: %d\n", vq->type); return -EINVAL; @@ -1715,7 +1747,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -1729,19 +1761,21 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state == MFCINST_RUNNING) && dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; - s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET, + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); } ctx->state = MFCINST_FINISHED; spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { cleanup_ref_queue(ctx); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -1782,7 +1816,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_enc_qops = { @@ -1880,3 +1914,13 @@ void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx) for (i = 0; i < NUM_CTRLS; i++) ctx->ctrls[i] = NULL; } + +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_ENC; + ctx->src_fmt = find_format(&f, MFC_FMT_RAW); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_ENC; + ctx->dst_fmt = find_format(&f, MFC_FMT_ENC); +} + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h index ca9fd66bd310..5118d46b3a9e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h @@ -19,5 +19,6 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_enc_def_fmt(bool src); int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx); #endif /* S5P_MFC_ENC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c index 37860e299021..5b8f0e085e6d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c @@ -17,7 +17,6 @@ #include <linux/io.h> #include <linux/sched.h> #include <linux/wait.h> -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" @@ -28,7 +27,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) ret = wait_event_interruptible_timeout(dev->queue, (dev->int_cond && (dev->int_type == command - || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || dev->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); if (ret == 0) { mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n", @@ -40,7 +39,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) } mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n", dev->int_type, command); - if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET) + if (dev->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; } @@ -60,12 +59,12 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, if (interrupt) { ret = wait_event_interruptible_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } else { ret = wait_event_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } if (ret == 0) { @@ -78,7 +77,7 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, } mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", ctx->int_type, command); - if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET) + if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 767a51271dc2..6932e90d4065 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -1,10 +1,10 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c + * drivers/media/platform/s5p-mfc/s5p_mfc_opr.c * * Samsung MFC (Multi Function Codec - FIMV) driver * This file contains hw related functions. * - * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -12,1414 +12,20 @@ * published by the Free Software Foundation. */ -#include "regs-mfc.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" -#include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" -#include <asm/cacheflush.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/firmware.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/mm.h> -#include <linux/sched.h> +#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr_v6.h" -#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) -#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) +static struct s5p_mfc_hw_ops *s5p_mfc_ops; -/* Allocate temporary buffers for decoding */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) { - void *desc_virt; - struct s5p_mfc_dev *dev = ctx->dev; - - ctx->desc_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE); - if (IS_ERR_VALUE((int)ctx->desc_buf)) { - ctx->desc_buf = NULL; - mfc_err("Allocating DESC buffer failed\n"); - return -ENOMEM; - } - ctx->desc_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf); - BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf); - if (desc_virt == NULL) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; - mfc_err("Remapping DESC buffer failed\n"); - return -ENOMEM; - } - memset(desc_virt, 0, DESC_BUF_SIZE); - wmb(); - return 0; -} - -/* Release temporary buffers for decoding */ -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - if (ctx->desc_phys) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; - } -} - -/* Allocate codec buffers */ -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int enc_ref_y_size = 0; - unsigned int enc_ref_c_size = 0; - unsigned int guard_width, guard_height; - - if (ctx->type == MFCINST_DECODER) { - mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", - ctx->luma_size, ctx->chroma_size, ctx->mv_size); - mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); - } else if (ctx->type == MFCINST_ENCODER) { - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height >> 1, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, - S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "recon luma size: %d chroma size: %d\n", - enc_ref_y_size, enc_ref_c_size); + if (IS_MFCV6(dev)) { + s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; } else { - return -EINVAL; - } - /* Codecs have different memory requirements */ - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + - S5P_FIMV_DEC_VERT_NB_MV_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; - break; - case S5P_FIMV_CODEC_MPEG4_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_STX_PARSER_SIZE + - S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_VC1RCV_DEC: - case S5P_FIMV_CODEC_VC1_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE + - 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_MPEG2_DEC: - ctx->bank1_size = 0; - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_H263_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_H264_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_INTRAMD_SIZE + - S5P_FIMV_ENC_NBORINFO_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4) + - S5P_FIMV_ENC_INTRAPRED_SIZE; - break; - case S5P_FIMV_CODEC_MPEG4_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - case S5P_FIMV_CODEC_H263_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - default: - break; - } - /* Allocate only if memory from bank 1 is necessary */ - if (ctx->bank1_size > 0) { - ctx->bank1_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); - if (IS_ERR(ctx->bank1_buf)) { - ctx->bank1_buf = NULL; - printk(KERN_ERR - "Buf alloc for decoding failed (port A)\n"); - return -ENOMEM; - } - ctx->bank1_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); - BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - } - /* Allocate only if memory from bank 2 is necessary */ - if (ctx->bank2_size > 0) { - ctx->bank2_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); - if (IS_ERR(ctx->bank2_buf)) { - ctx->bank2_buf = NULL; - mfc_err("Buf alloc for decoding failed (port B)\n"); - return -ENOMEM; - } - ctx->bank2_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); - BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); - } - return 0; -} - -/* Release buffers allocated for codec */ -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) -{ - if (ctx->bank1_buf) { - vb2_dma_contig_memops.put(ctx->bank1_buf); - ctx->bank1_buf = NULL; - ctx->bank1_phys = 0; - ctx->bank1_size = 0; - } - if (ctx->bank2_buf) { - vb2_dma_contig_memops.put(ctx->bank2_buf); - ctx->bank2_buf = NULL; - ctx->bank2_phys = 0; - ctx->bank2_size = 0; + s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; } + dev->mfc_ops = s5p_mfc_ops; } - -/* Allocate memory for instance data buffer */ -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) -{ - void *context_virt; - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - ctx->ctx_size = MFC_H264_CTX_BUF_SIZE; - else - ctx->ctx_size = MFC_CTX_BUF_SIZE; - ctx->ctx_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size); - if (IS_ERR(ctx->ctx_buf)) { - mfc_err("Allocating context buffer failed\n"); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - ctx->ctx_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf); - BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->ctx_ofs = OFFSETA(ctx->ctx_phys); - context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf); - if (context_virt == NULL) { - mfc_err("Remapping instance buffer failed\n"); - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - /* Zero content of the allocated memory */ - memset(context_virt, 0, ctx->ctx_size); - wmb(); - if (s5p_mfc_init_shm(ctx) < 0) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - return 0; -} - -/* Release instance buffer */ -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) -{ - if (ctx->ctx_buf) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - } - if (ctx->shm_alloc) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_alloc = NULL; - ctx->shm = NULL; - } -} - -/* Set registers for decoding temporary buffers */ -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR); - mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE); -} - -/* Set registers for shared buffer */ -static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); -} - -/* Set registers for decoding stream buffer */ -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, unsigned int buf_size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); - mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); - mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); - s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM); - return 0; -} - -/* Set decoding frame buffer */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) -{ - unsigned int frame_size, i; - unsigned int frame_size_ch, frame_size_mv; - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - size_t buf_addr1, buf_addr2; - int buf_size1, buf_size2; - - buf_addr1 = ctx->bank1_phys; - buf_size1 = ctx->bank1_size; - buf_addr2 = ctx->bank2_phys; - buf_size2 = ctx->bank2_size; - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~S5P_FIMV_DPB_COUNT_MASK; - mfc_write(dev, ctx->total_dpb_count | dpb, - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - s5p_mfc_set_shared_buffer(ctx); - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_VERT_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; - break; - case S5P_FIMV_CODEC_MPEG4_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); - buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; - buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - break; - case S5P_FIMV_CODEC_H263_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - break; - case S5P_FIMV_CODEC_VC1_DEC: - case S5P_FIMV_CODEC_VC1RCV_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - break; - case S5P_FIMV_CODEC_MPEG2_DEC: - break; - default: - mfc_err("Unknown codec for decoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - break; - } - frame_size = ctx->luma_size; - frame_size_ch = ctx->chroma_size; - frame_size_mv = ctx->mv_size; - mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, - frame_size_mv); - for (i = 0; i < ctx->total_dpb_count; i++) { - /* Bank2 */ - mfc_debug(2, "Luma %d: %x\n", i, - ctx->dst_bufs[i].cookie.raw.luma); - mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), - S5P_FIMV_DEC_LUMA_ADR + i * 4); - mfc_debug(2, "\tChroma %d: %x\n", i, - ctx->dst_bufs[i].cookie.raw.chroma); - mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), - S5P_FIMV_DEC_CHROMA_ADR + i * 4); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { - mfc_debug(2, "\tBuf2: %x, size: %d\n", - buf_addr2, buf_size2); - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_MV_ADR + i * 4); - buf_addr2 += frame_size_mv; - buf_size2 -= frame_size_mv; - } - } - mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); - mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", - buf_size1, buf_size2, ctx->total_dpb_count); - if (buf_size1 < 0 || buf_size2 < 0) { - mfc_debug(2, "Not enough memory has been allocated\n"); - return -ENOMEM; - } - s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); - s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) - s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE); - mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) - << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Set registers for encoding stream buffer */ -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); - mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); - return 0; -} - -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); - mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); -} - -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) - << MFC_OFFSET_SHIFT); - *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) - << MFC_OFFSET_SHIFT); -} - -/* Set encoding ref & codec buffer */ -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - size_t buf_addr1, buf_addr2; - size_t buf_size1, buf_size2; - unsigned int enc_ref_y_size, enc_ref_c_size; - unsigned int guard_width, guard_height; - int i; - - buf_addr1 = ctx->bank1_phys; - buf_size1 = ctx->bank1_size; - buf_addr2 = ctx->bank2_phys; - buf_size2 = ctx->bank2_size; - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_UP_INTRA_MD_ADR); - buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; - buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_UP_INTRA_PRED_ADR); - buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; - buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_NBOR_INFO_ADR); - buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; - buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - case S5P_FIMV_CODEC_MPEG4_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - case S5P_FIMV_CODEC_H263_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - default: - mfc_err("Unknown codec set for encoding: %d\n", - ctx->codec_mode); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - unsigned int reg; - unsigned int shm; - - /* width */ - mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); - /* height */ - mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); - /* pictype : enable, IDR period */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - reg |= (1 << 18); - reg &= ~(0xFFFF); - reg |= p->gop_size; - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); - /* multi-slice control */ - /* multi-slice MB number or bit size */ - mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { - mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { - mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); - } - /* cyclic intra refresh */ - mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - /* padding control & value */ - reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); - if (p->pad) { - /** enable */ - reg |= (1 << 31); - /** cr value */ - reg &= ~(0xFF << 16); - reg |= (p->pad_cr << 16); - /** cb value */ - reg &= ~(0xFF << 8); - reg |= (p->pad_cb << 8); - /** y value */ - reg &= ~(0xFF); - reg |= (p->pad_luma); - } else { - /** disable & all value clear */ - reg = 0; - } - mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /** frame-level rate control */ - reg &= ~(0x1 << 9); - reg |= (p->rc_frame << 9); - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* bit rate */ - if (p->rc_frame) - mfc_write(dev, p->rc_bitrate, - S5P_FIMV_ENC_RC_BIT_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); - /* reaction coefficient */ - if (p->rc_frame) - mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* seq header ctrl */ - shm &= ~(0x1 << 3); - shm |= (p->seq_hdr_mode << 3); - /* frame skip mode */ - shm &= ~(0x3 << 1); - shm |= (p->frame_skip_mode << 1); - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - /* fixed target bit */ - s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); - return 0; -} - -static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_264->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_264->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* interlace */ - mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT); - /* height */ - if (p->interlace) - mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); - /* loopfilter ctrl */ - mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); - /* loopfilter alpha offset */ - if (p_264->loop_filter_alpha < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_alpha) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_alpha & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); - /* loopfilter beta offset */ - if (p_264->loop_filter_beta < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_beta) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_beta & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); - /* entropy coding mode */ - if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) - mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); - /* number of ref. picture */ - reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* num of ref. pictures of P */ - reg &= ~(0x3 << 5); - reg |= (p_264->num_ref_pic_4p << 5); - /* max number of ref. pictures */ - reg &= ~(0x1F); - reg |= p_264->max_ref_pic; - mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* 8x8 transform enable */ - mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= (p_264->rc_mb << 8); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_264->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_264->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_264->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* macroblock adaptive scaling features */ - if (p_264->rc_mb) { - reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); - /* dark region */ - reg &= ~(0x1 << 3); - reg |= (p_264->rc_mb_dark << 3); - /* smooth region */ - reg &= ~(0x1 << 2); - reg |= (p_264->rc_mb_smooth << 2); - /* static region */ - reg &= ~(0x1 << 1); - reg |= (p_264->rc_mb_static << 1); - /* high activity region */ - reg &= ~(0x1); - reg |= p_264->rc_mb_activity; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); - } - if (!p->rc_frame && - !p_264->rc_mb) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_264->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* AR VUI control */ - shm &= ~(0x1 << 15); - shm |= (p_264->vui_sar << 1); - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - if (p_264->vui_sar) { - /* aspect ration IDC */ - shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC); - shm &= ~(0xFF); - shm |= p_264->vui_sar_idc; - s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); - if (p_264->vui_sar_idc == 0xFF) { - /* sample AR info */ - shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR); - shm &= ~(0xFFFFFFFF); - shm |= p_264->vui_ext_sar_width << 16; - shm |= p_264->vui_ext_sar_height; - s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR); - } - } - /* intra picture period for H.264 */ - shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD); - /* control */ - shm &= ~(0x1 << 16); - shm |= (p_264->open_gop << 16); - /* value */ - if (p_264->open_gop) { - shm &= ~(0xFFFF); - shm |= p_264->open_gop_size; - } - s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p_264->cpb_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - unsigned int framerate; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_mpeg4->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_mpeg4->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* quarter_pixel */ - mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame) { - if (p->rc_framerate_denom > 0) { - framerate = p->rc_framerate_num * 1000 / - p->rc_framerate_denom; - mfc_write(dev, framerate, - S5P_FIMV_ENC_RC_FRAME_RATE); - shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING); - shm &= ~(0xFFFFFFFF); - shm |= (1 << 31); - shm |= ((p->rc_framerate_num & 0x7FFF) << 16); - shm |= (p->rc_framerate_denom & 0xFFFF); - s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING); - } - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - } - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_mpeg4->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= (p_h263->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_h263->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -/* Initialize decoding */ -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_shared_buffer(ctx); - /* Setup loop filter, for decoding this is only valid for MPEG4 */ - if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) - mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); - else - mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); - mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << - S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << - S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & - S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - mfc_write(dev, - ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - - if (flush) - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( - S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - else - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); -} - -/* Decode a single frame */ -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); - s5p_mfc_set_shared_buffer(ctx); - s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); - /* Issue different commands to instance basing on whether it - * is the last frame or not. */ - switch (last_frame) { - case MFC_DEC_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_LAST_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_RES_CHANGE: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & - S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - break; - } - mfc_debug(2, "Decoding a usual frame\n"); - return 0; -} - -int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - s5p_mfc_set_enc_params_h264(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC) - s5p_mfc_set_enc_params_mpeg4(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC) - s5p_mfc_set_enc_params_h263(ctx); - else { - mfc_err("Unknown codec for encoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - } - s5p_mfc_set_shared_buffer(ctx); - mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | - (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Encode a single frame */ -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - int cmd; - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - s5p_mfc_set_shared_buffer(ctx); - - if (ctx->state == MFCINST_FINISHING) - cmd = S5P_FIMV_CH_LAST_FRAME; - else - cmd = S5P_FIMV_CH_FRAME_START; - mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - - return 0; -} - -static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) -{ - unsigned long flags; - int new_ctx; - int cnt; - - spin_lock_irqsave(&dev->condlock, flags); - new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; - cnt = 0; - while (!test_bit(new_ctx, &dev->ctx_work_bits)) { - new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; - if (++cnt > MFC_NUM_CONTEXTS) { - /* No contexts to run */ - spin_unlock_irqrestore(&dev->condlock, flags); - return -EAGAIN; - } - } - spin_unlock_irqrestore(&dev->condlock, flags); - return new_ctx; -} - -static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE); -} - -static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - unsigned long flags; - unsigned int index; - - spin_lock_irqsave(&dev->irqlock, flags); - /* Frames are being decoded */ - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "No src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - /* Get the next source buffer */ - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, - temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - index = temp_vb->b->v4l2_buf.index; - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - if (temp_vb->b->v4l2_planes[0].bytesused == 0) { - last_frame = MFC_DEC_LAST_FRAME; - mfc_debug(2, "Setting ctx->state to FINISHING\n"); - ctx->state = MFCINST_FINISHING; - } - s5p_mfc_decode_one_frame(ctx, last_frame); - return 0; -} - -static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *dst_mb; - struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; - unsigned int dst_size; - - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { - mfc_debug(2, "no src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - if (list_empty(&ctx->dst_queue)) { - mfc_debug(2, "no dst buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - if (list_empty(&ctx->src_queue)) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, dev->bank2); - src_mb = NULL; - } else { - src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); - src_mb->flags |= MFC_BUF_FLAG_USED; - if (src_mb->b->v4l2_planes[0].bytesused == 0) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, - dev->bank2); - ctx->state = MFCINST_FINISHING; - } else { - src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, - 0); - src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, - 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, - src_c_addr); - if (src_mb->flags & MFC_BUF_FLAG_EOS) - ctx->state = MFCINST_FINISHING; - } - } - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_mb->flags |= MFC_BUF_FLAG_USED; - dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); - dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - mfc_debug(2, "encoding buffer with index=%d state=%d", - src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); - s5p_mfc_encode_one_frame(ctx); - return 0; -} - -static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *temp_vb; - - /* Initializing decoding - parsing header */ - spin_lock_irqsave(&dev->irqlock, flags); - mfc_debug(2, "Preparing to init decoding\n"); - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - s5p_mfc_set_dec_desc_buffer(ctx); - mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), - 0, temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_decode(ctx); -} - -static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *dst_mb; - unsigned long dst_addr; - unsigned int dst_size; - - s5p_mfc_set_enc_ref_buffer(ctx); - spin_lock_irqsave(&dev->irqlock, flags); - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); - dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_encode(ctx); -} - -static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *temp_vb; - int ret; - - /* - * Header was parsed now starting processing - * First set the output frame buffers - */ - if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destionation buffers were " - "mmaped\nMFC requires that all destination are mmaped " - "before starting processing\n"); - return -EAGAIN; - } - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue)) { - mfc_err("Header has been deallocated in the middle of" - " initialization\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EIO; - } - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), - 0, temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_set_dec_frame_buffer(ctx); - if (ret) { - mfc_err("Failed to alloc frame mem\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -/* Try running an operation on hardware */ -void s5p_mfc_try_run(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_ctx *ctx; - int new_ctx; - unsigned int ret = 0; - - if (test_bit(0, &dev->enter_suspend)) { - mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); - return; - } - /* Check whether hardware is not running */ - if (test_and_set_bit(0, &dev->hw_lock) != 0) { - /* This is perfectly ok, the scheduled ctx should wait */ - mfc_debug(1, "Couldn't lock HW\n"); - return; - } - /* Choose the context to run */ - new_ctx = s5p_mfc_get_new_ctx(dev); - if (new_ctx < 0) { - /* No contexts to run */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) { - mfc_err("Failed to unlock hardware\n"); - return; - } - mfc_debug(1, "No ctx is scheduled to be run\n"); - return; - } - ctx = dev->ctx[new_ctx]; - /* Got context to run in ctx */ - /* - * Last frame has already been sent to MFC. - * Now obtaining frames from MFC buffer - */ - s5p_mfc_clock_on(); - if (ctx->type == MFCINST_DECODER) { - s5p_mfc_set_dec_desc_buffer(ctx); - switch (ctx->state) { - case MFCINST_FINISHING: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); - break; - case MFCINST_RUNNING: - ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); - break; - case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_dec(ctx); - break; - case MFCINST_HEAD_PARSED: - ret = s5p_mfc_run_init_dec_buffers(ctx); - mfc_debug(1, "head parsed\n"); - break; - case MFCINST_RES_CHANGE_INIT: - s5p_mfc_run_res_change(ctx); - break; - case MFCINST_RES_CHANGE_FLUSH: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_RES_CHANGE_END: - mfc_debug(2, "Finished remaining frames after resolution change\n"); - ctx->capture_state = QUEUE_FREE; - mfc_debug(2, "Will re-init the codec\n"); - s5p_mfc_run_init_dec(ctx); - break; - default: - ret = -EAGAIN; - } - } else if (ctx->type == MFCINST_ENCODER) { - switch (ctx->state) { - case MFCINST_FINISHING: - case MFCINST_RUNNING: - ret = s5p_mfc_run_enc_frame(ctx); - break; - case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); - break; - case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_enc(ctx); - break; - default: - ret = -EAGAIN; - } - } else { - mfc_err("Invalid context type: %d\n", ctx->type); - ret = -EAGAIN; - } - - if (ret) { - /* Free hardware lock */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - mfc_err("Failed to unlock hardware\n"); - - /* This is in deed imporant, as no operation has been - * scheduled, reduce the clock count as no one will - * ever do this, because no interrupt related to this try_run - * will ever come from hardware. */ - s5p_mfc_clock_off(); - } -} - - -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) -{ - struct s5p_mfc_buf *b; - int i; - - while (!list_empty(lh)) { - b = list_entry(lh->next, struct s5p_mfc_buf, list); - for (i = 0; i < b->b->num_planes; i++) - vb2_set_plane_payload(b->b, i, 0); - vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 2ad3def052f8..420abecafec0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -1,10 +1,10 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h + * drivers/media/platform/s5p-mfc/s5p_mfc_opr.h * * Header file for Samsung MFC (Multi Function Codec - FIMV) driver * Contains declarations of hw related functions. * - * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -17,77 +17,68 @@ #include "s5p_mfc_common.h" -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx); -int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx); +struct s5p_mfc_hw_ops { + int (*alloc_dec_temp_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_dec_desc_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_codec_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_codec_buffers)(struct s5p_mfc_ctx *ctx); + int (*alloc_instance_buffer)(struct s5p_mfc_ctx *ctx); + void (*release_instance_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx); + void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx); + int (*set_dec_stream_buffer)(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int buf_size); + int (*set_dec_frame_buffer)(struct s5p_mfc_ctx *ctx); + int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size); + void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr); + void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr); + int (*set_enc_ref_buffer)(struct s5p_mfc_ctx *ctx); + int (*init_decode)(struct s5p_mfc_ctx *ctx); + int (*init_encode)(struct s5p_mfc_ctx *ctx); + int (*encode_one_frame)(struct s5p_mfc_ctx *ctx); + void (*try_run)(struct s5p_mfc_dev *dev); + void (*cleanup_queue)(struct list_head *lh, + struct vb2_queue *vq); + void (*clear_int_flags)(struct s5p_mfc_dev *dev); + void (*write_info)(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs); + unsigned int (*read_info)(struct s5p_mfc_ctx *ctx, + unsigned int ofs); + int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dec_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dspl_status)(struct s5p_mfc_dev *dev); + int (*get_dec_status)(struct s5p_mfc_dev *dev); + int (*get_dec_frame_type)(struct s5p_mfc_dev *dev); + int (*get_disp_frame_type)(struct s5p_mfc_ctx *ctx); + int (*get_consumed_stream)(struct s5p_mfc_dev *dev); + int (*get_int_reason)(struct s5p_mfc_dev *dev); + int (*get_int_err)(struct s5p_mfc_dev *dev); + int (*err_dec)(unsigned int err); + int (*err_dspl)(unsigned int err); + int (*get_img_width)(struct s5p_mfc_dev *dev); + int (*get_img_height)(struct s5p_mfc_dev *dev); + int (*get_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_mv_count)(struct s5p_mfc_dev *dev); + int (*get_inst_no)(struct s5p_mfc_dev *dev); + int (*get_enc_strm_size)(struct s5p_mfc_dev *dev); + int (*get_enc_slice_type)(struct s5p_mfc_dev *dev); + int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_enc_pic_count)(struct s5p_mfc_dev *dev); + int (*get_sei_avail_status)(struct s5p_mfc_ctx *ctx); + int (*get_mvc_num_views)(struct s5p_mfc_dev *dev); + int (*get_mvc_view_id)(struct s5p_mfc_dev *dev); + unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); +}; -/* Decoding functions */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx); -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, - unsigned int buf_size); - -/* Encoding functions */ -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr); -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size); -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr); -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx); - -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame); -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx); - -/* Memory allocation */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx); - -void s5p_mfc_try_run(struct s5p_mfc_dev *dev); -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); - -#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_STATUS) -#define s5p_mfc_get_dec_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_STATUS) -#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \ - S5P_FIMV_DECODE_FRAME_TYPE) \ - & S5P_FIMV_DECODE_FRAME_MASK) -#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ - S5P_FIMV_SI_CONSUMED_BYTES) -#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_CMD) & \ - S5P_FIMV_RISC2HOST_CMD_MASK) -#define s5p_mfc_get_int_err() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG2) -#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \ - S5P_FIMV_ERR_DEC_SHIFT) -#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \ - S5P_FIMV_ERR_DSPL_SHIFT) -#define s5p_mfc_get_img_width() readl(dev->regs_base + \ - S5P_FIMV_SI_HRESOL) -#define s5p_mfc_get_img_height() readl(dev->regs_base + \ - S5P_FIMV_SI_VRESOL) -#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \ - S5P_FIMV_SI_BUF_NUMBER) -#define s5p_mfc_get_inst_no() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG1) -#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_STRM_SIZE) -#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_SLICE_TYPE) +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); #endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c new file mode 100644 index 000000000000..bf7d010a4107 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -0,0 +1,1794 @@ +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" +#include <asm/cacheflush.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/firmware.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/mm.h> +#include <linux/sched.h> + +#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) +#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) + +/* Allocate temporary buffers for decoding */ +int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + ctx->dsc.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], + buf_size->dsc); + if (IS_ERR_VALUE((int)ctx->dsc.alloc)) { + ctx->dsc.alloc = NULL; + mfc_err("Allocating DESC buffer failed\n"); + return -ENOMEM; + } + ctx->dsc.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->dsc.alloc); + BUG_ON(ctx->dsc.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->dsc.virt = vb2_dma_contig_memops.vaddr(ctx->dsc.alloc); + if (ctx->dsc.virt == NULL) { + vb2_dma_contig_memops.put(ctx->dsc.alloc); + ctx->dsc.dma = 0; + ctx->dsc.alloc = NULL; + mfc_err("Remapping DESC buffer failed\n"); + return -ENOMEM; + } + memset(ctx->dsc.virt, 0, buf_size->dsc); + wmb(); + return 0; +} + +/* Release temporary buffers for decoding */ +void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->dsc.dma) { + vb2_dma_contig_memops.put(ctx->dsc.alloc); + ctx->dsc.alloc = NULL; + ctx->dsc.dma = 0; + } +} + +/* Allocate codec buffers */ +int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int enc_ref_y_size = 0; + unsigned int enc_ref_c_size = 0; + unsigned int guard_width, guard_height; + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, + S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height >> 1, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, + S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + enc_ref_y_size, enc_ref_c_size); + } else { + return -EINVAL; + } + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + + S5P_FIMV_DEC_VERT_NB_MV_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_STX_PARSER_SIZE + + S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE + + 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1_size = 0; + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_INTRAMD_SIZE + + S5P_FIMV_ENC_NBORINFO_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4) + + S5P_FIMV_ENC_INTRAPRED_SIZE; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + case S5P_MFC_CODEC_H263_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + default: + break; + } + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1_size > 0) { + ctx->bank1_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); + if (IS_ERR(ctx->bank1_buf)) { + ctx->bank1_buf = NULL; + printk(KERN_ERR + "Buf alloc for decoding failed (port A)\n"); + return -ENOMEM; + } + ctx->bank1_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); + BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + /* Allocate only if memory from bank 2 is necessary */ + if (ctx->bank2_size > 0) { + ctx->bank2_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); + if (IS_ERR(ctx->bank2_buf)) { + ctx->bank2_buf = NULL; + mfc_err("Buf alloc for decoding failed (port B)\n"); + return -ENOMEM; + } + ctx->bank2_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); + BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); + } + return 0; +} + +/* Release buffers allocated for codec */ +void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->bank1_buf) { + vb2_dma_contig_memops.put(ctx->bank1_buf); + ctx->bank1_buf = NULL; + ctx->bank1_phys = 0; + ctx->bank1_size = 0; + } + if (ctx->bank2_buf) { + vb2_dma_contig_memops.put(ctx->bank2_buf); + ctx->bank2_buf = NULL; + ctx->bank2_phys = 0; + ctx->bank2_size = 0; + } +} + +/* Allocate memory for instance data buffer */ +int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + ctx->ctx.size = buf_size->h264_ctx; + else + ctx->ctx.size = buf_size->non_h264_ctx; + ctx->ctx.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); + if (IS_ERR(ctx->ctx.alloc)) { + mfc_err("Allocating context buffer failed\n"); + ctx->ctx.alloc = NULL; + return -ENOMEM; + } + ctx->ctx.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); + BUG_ON(ctx->ctx.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->ctx.ofs = OFFSETA(ctx->ctx.dma); + ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); + if (!ctx->ctx.virt) { + mfc_err("Remapping instance buffer failed\n"); + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.ofs = 0; + ctx->ctx.dma = 0; + return -ENOMEM; + } + /* Zero content of the allocated memory */ + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + /* Initialize shared memory */ + ctx->shm.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->shm); + if (IS_ERR(ctx->shm.alloc)) { + mfc_err("failed to allocate shared memory\n"); + return PTR_ERR(ctx->shm.alloc); + } + /* shared memory offset only keeps the offset from base (port a) */ + ctx->shm.ofs = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->shm.alloc) + - dev->bank1; + BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + + ctx->shm.virt = vb2_dma_contig_memops.vaddr(ctx->shm.alloc); + if (!ctx->shm.virt) { + vb2_dma_contig_memops.put(ctx->shm.alloc); + ctx->shm.alloc = NULL; + ctx->shm.ofs = 0; + mfc_err("failed to virt addr of shared memory\n"); + return -ENOMEM; + } + memset((void *)ctx->shm.virt, 0, buf_size->shm); + wmb(); + return 0; +} + +/* Release instance buffer */ +void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->ctx.alloc) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.ofs = 0; + ctx->ctx.virt = NULL; + ctx->ctx.dma = 0; + } + if (ctx->shm.alloc) { + vb2_dma_contig_memops.put(ctx->shm.alloc); + ctx->shm.alloc = NULL; + ctx->shm.ofs = 0; + ctx->shm.virt = NULL; + } +} + +int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + + return 0; +} + +void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ +} + +static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + writel(data, (ctx->shm.virt + ofs)); + wmb(); +} + +static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, + unsigned int ofs) +{ + rmb(); + return readl(ctx->shm.virt + ofs); +} + +void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) +{ + unsigned int guard_width, guard_height; + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + mfc_debug(2, + "SEQ Done: Movie dimensions %dx%d, buffer dimensions: %dx%d\n", + ctx->img_width, ctx->img_height, ctx->buf_width, + ctx->buf_height); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->chroma_size = ALIGN(ctx->buf_width * + ALIGN((ctx->img_height >> 1), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + ctx->mv_size = ALIGN(ctx->buf_width * + ALIGN((ctx->buf_height >> 2), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + } else { + guard_width = + ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN); + ctx->luma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + guard_width = + ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + ctx->mv_size = 0; + } +} + +void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12M_LVALIGN); + ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12M_CVALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12M_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12M_SALIGN); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = + ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12MT_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12MT_SALIGN); + } +} + +/* Set registers for decoding temporary buffers */ +static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + mfc_write(dev, OFFSETA(ctx->dsc.dma), S5P_FIMV_SI_CH0_DESC_ADR); + mfc_write(dev, buf_size->dsc, S5P_FIMV_SI_CH0_DESC_SIZE); +} + +/* Set registers for shared buffer */ +static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + mfc_write(dev, ctx->shm.ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); +} + +/* Set registers for decoding stream buffer */ +int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, unsigned int buf_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); + mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); + mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); + s5p_mfc_write_info_v5(ctx, start_num_byte, START_BYTE_NUM); + return 0; +} + +/* Set decoding frame buffer */ +int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + size_t buf_addr1, buf_addr2; + int buf_size1, buf_size2; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + buf_addr2 = ctx->bank2_phys; + buf_size2 = ctx->bank2_size; + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~S5P_FIMV_DPB_COUNT_MASK; + mfc_write(dev, ctx->total_dpb_count | dpb, + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + s5p_mfc_set_shared_buffer(ctx); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_VERT_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); + buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; + buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + break; + case S5P_MFC_CODEC_H263_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + break; + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + break; + default: + mfc_err("Unknown codec for decoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + break; + } + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, + frame_size_mv); + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), + S5P_FIMV_DEC_LUMA_ADR + i * 4); + mfc_debug(2, "\tChroma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), + S5P_FIMV_DEC_CHROMA_ADR + i * 4); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + mfc_debug(2, "\tBuf2: %x, size: %d\n", + buf_addr2, buf_size2); + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_MV_ADR + i * 4); + buf_addr2 += frame_size_mv; + buf_size2 -= frame_size_mv; + } + } + mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); + mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", + buf_size1, buf_size2, ctx->total_dpb_count); + if (buf_size1 < 0 || buf_size2 < 0) { + mfc_debug(2, "Not enough memory has been allocated\n"); + return -ENOMEM; + } + s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) + s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); + mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) + << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Set registers for encoding stream buffer */ +int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); + mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); + return 0; +} + +void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); + mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); +} + +void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) + << MFC_OFFSET_SHIFT); + *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) + << MFC_OFFSET_SHIFT); +} + +/* Set encoding ref & codec buffer */ +int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_addr2; + size_t buf_size1, buf_size2; + unsigned int enc_ref_y_size, enc_ref_c_size; + unsigned int guard_width, guard_height; + int i; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + buf_addr2 = ctx->bank2_phys; + buf_size2 = ctx->bank2_size; + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_UP_INTRA_MD_ADR); + buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; + buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_UP_INTRA_PRED_ADR); + buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; + buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_NBOR_INFO_ADR); + buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; + buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + case S5P_MFC_CODEC_MPEG4_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + case S5P_MFC_CODEC_H263_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + default: + mfc_err("Unknown codec set for encoding: %d\n", + ctx->codec_mode); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg; + unsigned int shm; + + /* width */ + mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); + /* height */ + mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); + /* pictype : enable, IDR period */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + reg |= (1 << 18); + reg &= ~(0xFFFF); + reg |= p->gop_size; + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); + /* multi-slice control */ + /* multi-slice MB number or bit size */ + mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); + } + /* cyclic intra refresh */ + mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + /* padding control & value */ + reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); + if (p->pad) { + /** enable */ + reg |= (1 << 31); + /** cr value */ + reg &= ~(0xFF << 16); + reg |= (p->pad_cr << 16); + /** cb value */ + reg &= ~(0xFF << 8); + reg |= (p->pad_cb << 8); + /** y value */ + reg &= ~(0xFF); + reg |= (p->pad_luma); + } else { + /** disable & all value clear */ + reg = 0; + } + mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /** frame-level rate control */ + reg &= ~(0x1 << 9); + reg |= (p->rc_frame << 9); + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* bit rate */ + if (p->rc_frame) + mfc_write(dev, p->rc_bitrate, + S5P_FIMV_ENC_RC_BIT_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); + /* reaction coefficient */ + if (p->rc_frame) + mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* seq header ctrl */ + shm &= ~(0x1 << 3); + shm |= (p->seq_hdr_mode << 3); + /* frame skip mode */ + shm &= ~(0x3 << 1); + shm |= (p->frame_skip_mode << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + /* fixed target bit */ + s5p_mfc_write_info_v5(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_264->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_264->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* interlace */ + mfc_write(dev, p_264->interlace, S5P_FIMV_ENC_PIC_STRUCT); + /* height */ + if (p_264->interlace) + mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); + /* loopfilter ctrl */ + mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); + /* loopfilter alpha offset */ + if (p_264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_alpha & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); + /* loopfilter beta offset */ + if (p_264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_beta & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); + /* entropy coding mode */ + if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); + /* number of ref. picture */ + reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* num of ref. pictures of P */ + reg &= ~(0x3 << 5); + reg |= (p_264->num_ref_pic_4p << 5); + /* max number of ref. pictures */ + reg &= ~(0x1F); + reg |= p_264->max_ref_pic; + mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* 8x8 transform enable */ + mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_264->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_264->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_264->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* macroblock adaptive scaling features */ + if (p->rc_mb) { + reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); + /* dark region */ + reg &= ~(0x1 << 3); + reg |= (p_264->rc_mb_dark << 3); + /* smooth region */ + reg &= ~(0x1 << 2); + reg |= (p_264->rc_mb_smooth << 2); + /* static region */ + reg &= ~(0x1 << 1); + reg |= (p_264->rc_mb_static << 1); + /* high activity region */ + reg &= ~(0x1); + reg |= p_264->rc_mb_activity; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); + } + if (!p->rc_frame && !p->rc_mb) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_264->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* AR VUI control */ + shm &= ~(0x1 << 15); + shm |= (p_264->vui_sar << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + if (p_264->vui_sar) { + /* aspect ration IDC */ + shm = s5p_mfc_read_info_v5(ctx, SAMPLE_ASPECT_RATIO_IDC); + shm &= ~(0xFF); + shm |= p_264->vui_sar_idc; + s5p_mfc_write_info_v5(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); + if (p_264->vui_sar_idc == 0xFF) { + /* sample AR info */ + shm = s5p_mfc_read_info_v5(ctx, EXTENDED_SAR); + shm &= ~(0xFFFFFFFF); + shm |= p_264->vui_ext_sar_width << 16; + shm |= p_264->vui_ext_sar_height; + s5p_mfc_write_info_v5(ctx, shm, EXTENDED_SAR); + } + } + /* intra picture period for H.264 */ + shm = s5p_mfc_read_info_v5(ctx, H264_I_PERIOD); + /* control */ + shm &= ~(0x1 << 16); + shm |= (p_264->open_gop << 16); + /* value */ + if (p_264->open_gop) { + shm &= ~(0xFFFF); + shm |= p_264->open_gop_size; + } + s5p_mfc_write_info_v5(ctx, shm, H264_I_PERIOD); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p_264->cpb_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + unsigned int framerate; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_mpeg4->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_mpeg4->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* quarter_pixel */ + mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame) { + if (p->rc_framerate_denom > 0) { + framerate = p->rc_framerate_num * 1000 / + p->rc_framerate_denom; + mfc_write(dev, framerate, + S5P_FIMV_ENC_RC_FRAME_RATE); + shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING); + shm &= ~(0xFFFFFFFF); + shm |= (1 << 31); + shm |= ((p->rc_framerate_num & 0x7FFF) << 16); + shm |= (p->rc_framerate_denom & 0xFFFF); + s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING); + } + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + } + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_mpeg4->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= (p_h263->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_h263->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +/* Initialize decoding */ +int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_shared_buffer(ctx); + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) + mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); + else + mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); + mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << + S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << + S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & + S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + mfc_write(dev, + ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + + if (flush) + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( + S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + else + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); + s5p_mfc_set_shared_buffer(ctx); + s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case MFC_DEC_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_LAST_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_RES_CHANGE: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & + S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + break; + } + mfc_debug(2, "Decoding a usual frame\n"); + return 0; +} + +int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + } + s5p_mfc_set_shared_buffer(ctx); + mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | + (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Encode a single frame */ +int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int cmd; + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + s5p_mfc_set_shared_buffer(ctx); + + if (ctx->state == MFCINST_FINISHING) + cmd = S5P_FIMV_CH_LAST_FRAME; + else + cmd = S5P_FIMV_CH_FRAME_START; + mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + + return 0; +} + +static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int new_ctx; + int cnt; + + spin_lock_irqsave(&dev->condlock, flags); + new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; + cnt = 0; + while (!test_bit(new_ctx, &dev->ctx_work_bits)) { + new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; + if (++cnt > MFC_NUM_CONTEXTS) { + /* No contexts to run */ + spin_unlock_irqrestore(&dev->condlock, flags); + return -EAGAIN; + } + } + spin_unlock_irqrestore(&dev->condlock, flags); + return new_ctx; +} + +static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE); +} + +static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + index = temp_vb->b->v4l2_buf.index; + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + if (temp_vb->b->v4l2_planes[0].bytesused == 0) { + last_frame = MFC_DEC_LAST_FRAME; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v5(ctx, last_frame); + return 0; +} + +static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + unsigned int dst_size; + + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { + mfc_debug(2, "no src buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + if (list_empty(&ctx->src_queue)) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, dev->bank2); + src_mb = NULL; + } else { + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, + list); + src_mb->flags |= MFC_BUF_FLAG_USED; + if (src_mb->b->v4l2_planes[0].bytesused == 0) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, + dev->bank2); + ctx->state = MFCINST_FINISHING; + } else { + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, + 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, + 1); + s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr, + src_c_addr); + if (src_mb->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; + } + } + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + mfc_debug(2, "encoding buffer with index=%d state=%d", + src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); + s5p_mfc_encode_one_frame_v5(ctx); + return 0; +} + +static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + spin_lock_irqsave(&dev->irqlock, flags); + mfc_debug(2, "Preparing to init decoding\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + s5p_mfc_set_dec_desc_buffer(ctx); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + 0, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_decode_v5(ctx); +} + +static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + s5p_mfc_set_enc_ref_buffer_v5(ctx); + spin_lock_irqsave(&dev->irqlock, flags); + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_encode_v5(ctx); +} + +static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + int ret; + + /* + * Header was parsed now starting processing + * First set the output frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destionation buffers were " + "mmaped\nMFC requires that all destination are mmaped " + "before starting processing\n"); + return -EAGAIN; + } + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue)) { + mfc_err("Header has been deallocated in the middle of" + " initialization\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EIO; + } + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + 0, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + if (test_bit(0, &dev->enter_suspend)) { + mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); + return; + } + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW\n"); + return; + } + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware\n"); + return; + } + mfc_debug(1, "No ctx is scheduled to be run\n"); + return; + } + ctx = dev->ctx[new_ctx]; + /* Got context to run in ctx */ + /* + * Last frame has already been sent to MFC. + * Now obtaining frames from MFC buffer + */ + s5p_mfc_clock_on(); + if (ctx->type == MFCINST_DECODER) { + s5p_mfc_set_dec_desc_buffer(ctx); + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + mfc_debug(1, "head parsed\n"); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_res_change(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("Invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + + +void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->num_planes; i++) + vb2_set_plane_payload(b->b, i, 0); + vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + +void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); +} + +int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT; +} + +int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT; +} + +int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS); +} + +int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS); +} + +int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) +{ + return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >> + S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES); +} + +int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) +{ + int reason; + reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) & + S5P_FIMV_RISC2HOST_CMD_MASK; + switch (reason) { + case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + reason = S5P_MFC_R2H_CMD_SEQ_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + reason = S5P_MFC_R2H_CMD_FRAME_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: + reason = S5P_MFC_R2H_CMD_SLICE_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SYS_INIT_RET: + reason = S5P_MFC_R2H_CMD_SYS_INIT_RET; + break; + case S5P_FIMV_R2H_CMD_FW_STATUS_RET: + reason = S5P_MFC_R2H_CMD_FW_STATUS_RET; + break; + case S5P_FIMV_R2H_CMD_SLEEP_RET: + reason = S5P_MFC_R2H_CMD_SLEEP_RET; + break; + case S5P_FIMV_R2H_CMD_WAKEUP_RET: + reason = S5P_MFC_R2H_CMD_WAKEUP_RET; + break; + case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + reason = S5P_MFC_R2H_CMD_INIT_BUFFERS_RET; + break; + case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + reason = S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET; + break; + case S5P_FIMV_R2H_CMD_ERR_RET: + reason = S5P_MFC_R2H_CMD_ERR_RET; + break; + default: + reason = S5P_MFC_R2H_CMD_EMPTY; + }; + return reason; +} + +int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2); +} + +int s5p_mfc_err_dec_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; +} + +int s5p_mfc_err_dspl_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT; +} + +int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_HRESOL); +} + +int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_VRESOL); +} + +int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER); +} + +int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1); +} + +int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE); +} + +int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE); +} + +int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT); +} + +int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL); +} + +int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); +} + +unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT); +} + +unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_H); +} + +unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_V); +} + +/* Initialize opr function pointers for MFC v5 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v5, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v5, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v5, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v5, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v5, + .alloc_dev_context_buffer = s5p_mfc_alloc_dev_context_buffer_v5, + .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5, + .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v5, + .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v5, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5, + .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v5, + .init_decode = s5p_mfc_init_decode_v5, + .init_encode = s5p_mfc_init_encode_v5, + .encode_one_frame = s5p_mfc_encode_one_frame_v5, + .try_run = s5p_mfc_try_run_v5, + .cleanup_queue = s5p_mfc_cleanup_queue_v5, + .clear_int_flags = s5p_mfc_clear_int_flags_v5, + .write_info = s5p_mfc_write_info_v5, + .read_info = s5p_mfc_read_info_v5, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5, + .get_dspl_status = s5p_mfc_get_dspl_status_v5, + .get_dec_status = s5p_mfc_get_dec_status_v5, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v5, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v5, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v5, + .get_int_reason = s5p_mfc_get_int_reason_v5, + .get_int_err = s5p_mfc_get_int_err_v5, + .err_dec = s5p_mfc_err_dec_v5, + .err_dspl = s5p_mfc_err_dspl_v5, + .get_img_width = s5p_mfc_get_img_width_v5, + .get_img_height = s5p_mfc_get_img_height_v5, + .get_dpb_count = s5p_mfc_get_dpb_count_v5, + .get_mv_count = s5p_mfc_get_mv_count_v5, + .get_inst_no = s5p_mfc_get_inst_no_v5, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5, + .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v5, + .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v5, + .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v5, + .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v5, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v5, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v5, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v5, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) +{ + return &s5p_mfc_ops_v5; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h index 416ebd7ba35a..ffee39a127d5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h @@ -1,17 +1,22 @@ /* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ -#ifndef S5P_MFC_SHM_H_ -#define S5P_MFC_SHM_H_ +#ifndef S5P_MFC_OPR_V5_H_ +#define S5P_MFC_OPR_V5_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" enum MFC_SHM_OFS { EXTENEDED_DECODE_STATUS = 0x00, /* D */ @@ -71,20 +76,10 @@ enum MFC_SHM_OFS { DBG_HISTORY_INPUT1 = 0xD4, /* C */ DBG_HISTORY_OUTPUT = 0xD8, /* C */ HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ + FRAME_PACK_SEI_ENABLE = 0x168, /* C */ + FRAME_PACK_SEI_AVAIL = 0x16c, /* D */ + FRAME_PACK_SEI_INFO = 0x17c, /* E */ }; -int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx); - -#define s5p_mfc_write_shm(ctx, x, ofs) \ - do { \ - writel(x, (ctx->shm + ofs)); \ - wmb(); \ - } while (0) - -static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs) -{ - rmb(); - return readl(ctx->shm + ofs); -} - -#endif /* S5P_MFC_SHM_H_ */ +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); +#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c new file mode 100644 index 000000000000..50b5bee3c44e --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -0,0 +1,1956 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#undef DEBUG + +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/firmware.h> +#include <linux/err.h> +#include <linux/sched.h> +#include <linux/dma-mapping.h> + +#include <asm/cacheflush.h> + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v6.h" + +/* #define S5P_MFC_DEBUG_REGWRITE */ +#ifdef S5P_MFC_DEBUG_REGWRITE +#undef writel +#define writel(v, r) \ + do { \ + pr_err("MFCWRITE(%p): %08x\n", r, (unsigned int)v); \ + __raw_writel(v, r); \ + } while (0) +#endif /* S5P_MFC_DEBUG_REGWRITE */ + +#define READL(offset) readl(dev->regs_base + (offset)) +#define WRITEL(data, offset) writel((data), dev->regs_base + (offset)) +#define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET) +#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET) + +/* Allocate temporary buffers for decoding */ +int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ + + return 0; +} + +/* Release temproary buffers for decoding */ +void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ +} + +int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +/* Allocate codec buffers */ +int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * + ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), + S5P_FIMV_TMV_BUFFER_ALIGN_V6); + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( + ctx->img_width, ctx->img_height, + mb_width, mb_height), + S5P_FIMV_ME_BUFFER_ALIGN_V6); + + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + ctx->luma_dpb_size, ctx->chroma_dpb_size); + } else { + return -EINVAL; + } + + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_MPEG4_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1_size = 0; + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VP8_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->dpb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->dpb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2_size = 0; + break; + default: + break; + } + + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1_size > 0) { + ctx->bank1_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); + if (IS_ERR(ctx->bank1_buf)) { + ctx->bank1_buf = 0; + pr_err("Buf alloc for decoding failed (port A)\n"); + return -ENOMEM; + } + ctx->bank1_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); + BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + + return 0; +} + +/* Release buffers allocated for codec */ +void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + if (ctx->bank1_buf) { + vb2_dma_contig_memops.put(ctx->bank1_buf); + ctx->bank1_buf = 0; + ctx->bank1_phys = 0; + ctx->bank1_size = 0; + } +} + +/* Allocate memory for instance data buffer */ +int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + mfc_debug_enter(); + + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + ctx->ctx.size = buf_size->h264_dec_ctx; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + case S5P_MFC_CODEC_H263_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_MPEG2_DEC: + case S5P_MFC_CODEC_VP8_DEC: + ctx->ctx.size = buf_size->other_dec_ctx; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->ctx.size = buf_size->h264_enc_ctx; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + ctx->ctx.size = buf_size->other_enc_ctx; + break; + default: + ctx->ctx.size = 0; + mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode); + break; + } + + ctx->ctx.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); + if (IS_ERR(ctx->ctx.alloc)) { + mfc_err("Allocating context buffer failed.\n"); + return PTR_ERR(ctx->ctx.alloc); + } + + ctx->ctx.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); + + ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); + if (!ctx->ctx.virt) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.dma = 0; + ctx->ctx.virt = NULL; + + mfc_err("Remapping context buffer failed.\n"); + return -ENOMEM; + } + + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release instance buffer */ +void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + mfc_debug_enter(); + + if (ctx->ctx.alloc) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.dma = 0; + ctx->ctx.virt = NULL; + } + + mfc_debug_leave(); +} + +/* Allocate context buffers for SYS_INIT */ +int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + mfc_debug_enter(); + + dev->ctx_buf.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->dev_ctx); + if (IS_ERR(dev->ctx_buf.alloc)) { + mfc_err("Allocating DESC buffer failed.\n"); + return PTR_ERR(dev->ctx_buf.alloc); + } + + dev->ctx_buf.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], + dev->ctx_buf.alloc); + + dev->ctx_buf.virt = vb2_dma_contig_memops.vaddr(dev->ctx_buf.alloc); + if (!dev->ctx_buf.virt) { + vb2_dma_contig_memops.put(dev->ctx_buf.alloc); + dev->ctx_buf.alloc = NULL; + dev->ctx_buf.dma = 0; + + mfc_err("Remapping DESC buffer failed.\n"); + return -ENOMEM; + } + + memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release context buffers for SYS_INIT */ +void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + if (dev->ctx_buf.alloc) { + vb2_dma_contig_memops.put(dev->ctx_buf.alloc); + dev->ctx_buf.alloc = NULL; + dev->ctx_buf.dma = 0; + dev->ctx_buf.virt = NULL; + } +} + +static int calc_plane(int width, int height) +{ + int mbX, mbY; + + mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); + mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6); + + if (width * height < S5P_FIMV_MAX_FRAME_SIZE_V6) + mbY = (mbY + 1) / 2 * 2; + + return (mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6) * + (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); +} + +void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) +{ + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); + mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" + "buffer dimensions: %dx%d\n", ctx->img_width, + ctx->img_height, ctx->buf_width, ctx->buf_height); + + ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); + ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); + ctx->mv_size = ALIGN(ctx->mv_size, 16); + } else { + ctx->mv_size = 0; + } +} + +void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6); + ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256); + ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256); +} + +/* Set registers for decoding stream buffer */ +int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, unsigned int strm_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + + mfc_debug_enter(); + mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" + "buf_size: 0x%08x (%d)\n", + ctx->inst_no, buf_addr, strm_size, strm_size); + WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6); + WRITEL(buf_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6); + WRITEL(buf_size->cpb, S5P_FIMV_D_CPB_BUFFER_SIZE_V6); + WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6); + + mfc_debug_leave(); + return 0; +} + +/* Set decoding frame buffer */ +int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1; + int buf_size1; + int align_gap; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); + mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); + + WRITEL(ctx->total_dpb_count, S5P_FIMV_D_NUM_DPB_V6); + WRITEL(ctx->luma_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6); + WRITEL(ctx->chroma_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6); + + WRITEL(buf_addr1, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6); + WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ + WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6); + WRITEL(ctx->mv_count, S5P_FIMV_D_NUM_MV_V6); + } + + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", + frame_size, frame_size_ch, frame_size_mv); + + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + WRITEL(ctx->dst_bufs[i].cookie.raw.luma, + S5P_FIMV_D_LUMA_DPB_V6 + i * 4); + mfc_debug(2, "\tChroma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + WRITEL(ctx->dst_bufs[i].cookie.raw.chroma, + S5P_FIMV_D_CHROMA_DPB_V6 + i * 4); + } + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + for (i = 0; i < ctx->mv_count; i++) { + /* To test alignment */ + align_gap = buf_addr1; + buf_addr1 = ALIGN(buf_addr1, 16); + align_gap = buf_addr1 - align_gap; + buf_size1 -= align_gap; + + mfc_debug(2, "\tBuf1: %x, size: %d\n", + buf_addr1, buf_size1); + WRITEL(buf_addr1, S5P_FIMV_D_MV_BUFFER_V6 + i * 4); + buf_addr1 += frame_size_mv; + buf_size1 -= frame_size_mv; + } + } + + mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n", + buf_addr1, buf_size1, ctx->total_dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug(2, "After setting buffers.\n"); + return 0; +} + +/* Set registers for encoding stream buffer */ +int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); /* 16B align */ + WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); + + mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d", + addr, size); + + return 0; +} + +void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); /* 256B align */ + WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); + + mfc_debug(2, "enc src y buf addr: 0x%08lx", y_addr); + mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr); +} + +void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long enc_recon_y_addr, enc_recon_c_addr; + + *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6); + *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6); + + enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); + enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); + + mfc_debug(2, "recon y addr: 0x%08lx", enc_recon_y_addr); + mfc_debug(2, "recon c addr: 0x%08lx", enc_recon_c_addr); +} + +/* Set encoding ref & codec buffer */ +int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_size1; + int i; + + mfc_debug_enter(); + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + + for (i = 0; i < ctx->dpb_count; i++) { + WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER_V6 + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } + + WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); + WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER0_V6); + buf_addr1 += ctx->tmv_buffer_size >> 1; + WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER1_V6); + buf_addr1 += ctx->tmv_buffer_size >> 1; + buf_size1 -= ctx->tmv_buffer_size; + + mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", + buf_addr1, buf_size1, ctx->dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + WRITEL(ctx->slice_mode, S5P_FIMV_E_MSLICE_MODE_V6); + if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + WRITEL(ctx->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + } else if (ctx->slice_mode == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + WRITEL(ctx->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + } else { + WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + } + + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg = 0; + + mfc_debug_enter(); + + /* width */ + WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH_V6); /* 16 align */ + /* height */ + WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT_V6); /* 16 align */ + + /* cropped width */ + WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6); + /* cropped height */ + WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + /* cropped offset */ + WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET_V6); + + /* pictype : IDR period */ + reg = 0; + reg |= p->gop_size & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + ctx->slice_mode = p->slice_mode; + reg = 0; + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + reg |= (0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + ctx->slice_size.mb = p->slice_mb; + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + reg |= (0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + ctx->slice_size.bits = p->slice_bit; + } else { + reg &= ~(0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + } + + s5p_mfc_set_slice_mode(ctx); + + /* cyclic intra refresh */ + WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE_V6); + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + if (p->intra_refresh_mb == 0) + reg &= ~(0x1 << 4); + else + reg |= (0x1 << 4); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 9); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg |= (0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + } + + /* memory structure recon. frame */ + /* 0: Linear, 1: 2D tiled */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg |= (0x1 << 8); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* padding control & value */ + WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL_V6); + if (p->pad) { + reg = 0; + /** enable */ + reg |= (1 << 31); + /** cr value */ + reg |= ((p->pad_cr & 0xFF) << 16); + /** cb value */ + reg |= ((p->pad_cb & 0xFF) << 8); + /** y value */ + reg |= p->pad_luma & 0xFF; + WRITEL(reg, S5P_FIMV_E_PADDING_CTRL_V6); + } + + /* rate control config. */ + reg = 0; + /* frame-level rate control */ + reg |= ((p->rc_frame & 0x1) << 9); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* bit rate */ + if (p->rc_frame) + WRITEL(p->rc_bitrate, + S5P_FIMV_E_RC_BIT_RATE_V6); + else + WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6); + + /* reaction coefficient */ + if (p->rc_frame) { + if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ + WRITEL(1, S5P_FIMV_E_RC_RPARAM_V6); + else /* loose CBR */ + WRITEL(2, S5P_FIMV_E_RC_RPARAM_V6); + } + + /* seq header ctrl */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 2); + reg |= ((p->seq_hdr_mode & 0x1) << 2); + + /* frame skip mode */ + reg &= ~(0x3); + reg |= (p->frame_skip_mode & 0x3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* 'DROP_CONTROL_ENABLE', disable */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + reg &= ~(0x1 << 10); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* setting for MV range [16, 256] */ + reg = 0; + reg &= ~(0x3FFF); + reg = 256; + WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE_V6); + + reg = 0; + reg &= ~(0x3FFF); + reg = 256; + WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE_V6); + + WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION_V6); + WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR_V6); + WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE_V6); + WRITEL(0x0, S5P_FIMV_E_RC_ROI_CTRL_V6); + WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG_V6); + + WRITEL(0x0, S5P_FIMV_E_BIT_COUNT_ENABLE_V6); + WRITEL(0x0, S5P_FIMV_E_MAX_BIT_COUNT_V6); + WRITEL(0x0, S5P_FIMV_E_MIN_BIT_COUNT_V6); + + WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6); + WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_h264->level & 0xFF) << 8); + /** profile - 0 ~ 3 */ + reg |= p_h264->profile & 0x3F; + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h264->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h264->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h264->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h264->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p_h264->cpb_size & 0xFFFF, + S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + /* interlace */ + reg = 0; + reg |= ((p_h264->interlace & 0x1) << 3); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* height */ + if (p_h264->interlace) { + WRITEL(ctx->img_height >> 1, + S5P_FIMV_E_FRAME_HEIGHT_V6); /* 32 align */ + /* cropped height */ + WRITEL(ctx->img_height >> 1, + S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + } + + /* loop filter ctrl */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 1); + reg |= ((p_h264->loop_filter_mode & 0x3) << 1); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* loopfilter alpha offset */ + if (p_h264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_alpha & 0xF); + } + WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6); + + /* loopfilter beta offset */ + if (p_h264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_beta & 0xF); + } + WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6); + + /* entropy coding mode */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1); + reg |= p_h264->entropy_mode & 0x1; + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* number of ref. picture */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 7); + reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* 8x8 transform enable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 12); + reg |= ((p_h264->_8x8_transform & 0x3) << 12); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* macroblock adaptive scaling features */ + WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG_V6); + if (p->rc_mb) { + reg = 0; + /** dark region */ + reg |= ((p_h264->rc_mb_dark & 0x1) << 3); + /** smooth region */ + reg |= ((p_h264->rc_mb_smooth & 0x1) << 2); + /** static region */ + reg |= ((p_h264->rc_mb_static & 0x1) << 1); + /** high activity region */ + reg |= p_h264->rc_mb_activity & 0x1; + WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG_V6); + } + + /* aspect ratio VUI */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 5); + reg |= ((p_h264->vui_sar & 0x1) << 5); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO_V6); + WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR_V6); + if (p_h264->vui_sar) { + /* aspect ration IDC */ + reg = 0; + reg |= p_h264->vui_sar_idc & 0xFF; + WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO_V6); + if (p_h264->vui_sar_idc == 0xFF) { + /* extended SAR */ + reg = 0; + reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; + reg |= p_h264->vui_ext_sar_height & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR_V6); + } + } + + /* intra picture period for H.264 open GOP */ + /* control */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 4); + reg |= ((p_h264->open_gop & 0x1) << 4); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + /* value */ + WRITEL(0x0, S5P_FIMV_E_H264_I_PERIOD_V6); + if (p_h264->open_gop) { + reg = 0; + reg |= p_h264->open_gop_size & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_H264_I_PERIOD_V6); + } + + /* 'WEIGHTED_BI_PREDICTION' for B is disable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 9); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 14); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* ASO */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 6); + reg |= ((p_h264->aso & 0x1) << 6); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* hier qp enable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 8); + reg |= ((p_h264->open_gop & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + reg = 0; + if (p_h264->hier_qp && p_h264->hier_qp_layer) { + reg |= (p_h264->hier_qp_type & 0x1) << 0x3; + reg |= p_h264->hier_qp_layer & 0x7; + WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + /* QP value for each layer */ + for (i = 0; i < (p_h264->hier_qp_layer & 0x7); i++) + WRITEL(p_h264->hier_qp_layer_qp[i], + S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 + + i * 4); + } + /* number of coding layer should be zero when hierarchical is disable */ + WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + + /* frame packing SEI generation */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 25); + reg |= ((p_h264->sei_frame_packing & 0x1) << 25); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + if (p_h264->sei_frame_packing) { + reg = 0; + /** current frame0 flag */ + reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); + /** arrangement type */ + reg |= p_h264->sei_fp_arrangement_type & 0x3; + WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6); + } + + if (p_h264->fmo) { + switch (p_h264->fmo_map_type) { + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) + WRITEL(p_h264->fmo_run_len[i] - 1, + S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 + + i * 4); + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: + if (p_h264->fmo_slice_grp > 2) + p_h264->fmo_slice_grp = 2; + WRITEL(p_h264->fmo_chg_dir & 0x1, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6); + /* the valid range is 0 ~ number of macroblocks -1 */ + WRITEL(p_h264->fmo_chg_rate, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6); + break; + default: + mfc_err("Unsupported map type for FMO: %d\n", + p_h264->fmo_map_type); + p_h264->fmo_map_type = 0; + p_h264->fmo_slice_grp = 1; + break; + } + + WRITEL(p_h264->fmo_map_type, + S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6); + WRITEL(p_h264->fmo_slice_grp - 1, + S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + } else { + WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + } + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_mpeg4->level & 0xFF) << 8); + /** profile - 0 ~ 1 */ + reg |= p_mpeg4->profile & 0x3F; + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_mpeg4->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + /* Disable HEC */ + WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS_V6); + WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* profile & level */ + reg = 0; + /** profile */ + reg |= (0x1 << 4); + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h263->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h263->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h263->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + mfc_debug_leave(); + + return 0; +} + +/* Initialize decoding */ +int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int reg = 0; + int fmo_aso_ctrl = 0; + + mfc_debug_enter(); + mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, + S5P_FIMV_CH_SEQ_HEADER_V6); + mfc_debug(2, "BUFs: %08x %08x %08x\n", + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6)); + + /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ + reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); + + /* When user sets desplay_delay to 0, + * It works as "display_delay enable" and delay set to 0. + * If user wants display_delay disable, It should be + * set to negative value. */ + if (ctx->display_delay >= 0) { + reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); + WRITEL(ctx->display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6); + } + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) { + mfc_debug(2, "Set loop filter to: %d\n", + ctx->loop_filter_mpeg4); + reg |= (ctx->loop_filter_mpeg4 << + S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6); + } + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) + reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); + + WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6); + + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) + WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); + else + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + + /* sei parse */ + WRITEL(ctx->sei_fp_parse & 0x1, S5P_FIMV_D_SEI_ENABLE_V6); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + mfc_debug_leave(); + return 0; +} + +static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + if (flush) + dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14); + else + dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14); + WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(ctx->dec_dst_flag, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6); + WRITEL(ctx->slice_interface & 0x1, S5P_FIMV_D_SLICE_IF_ENABLE_V6); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case 0: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + break; + case 1: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_LAST_FRAME_V6, NULL); + break; + default: + mfc_err("Unsupported last frame arg.\n"); + return -EINVAL; + } + + mfc_debug(2, "Decoding a usual frame.\n"); + return 0; +} + +int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x).\n", + ctx->codec_mode); + return -EINVAL; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + return 0; +} + +int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + int i; + + if (p_h264->aso) { + for (i = 0; i < 8; i++) + WRITEL(p_h264->aso_slice_order[i], + S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 + i * 4); + } + return 0; +} + +/* Encode a single frame */ +int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_debug(2, "++\n"); + + /* memory structure cur. frame */ + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_h264_set_aso_slice_order_v6(ctx); + + s5p_mfc_set_slice_mode(ctx); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + + mfc_debug(2, "--\n"); + + return 0; +} + +static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int new_ctx; + int cnt; + + spin_lock_irqsave(&dev->condlock, flags); + mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx, + dev->ctx_work_bits); + new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; + cnt = 0; + while (!test_bit(new_ctx, &dev->ctx_work_bits)) { + new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; + cnt++; + if (cnt > MFC_NUM_CONTEXTS) { + /* No contexts to run */ + spin_unlock_irqrestore(&dev->condlock, flags); + return -EAGAIN; + } + } + spin_unlock_irqrestore(&dev->condlock, flags); + return new_ctx; +} + +static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, 0); + spin_unlock_irqrestore(&dev->irqlock, flags); + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v6(ctx, 1); +} + +static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + int last_frame = 0; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + ctx->consumed_stream, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + + index = temp_vb->b->v4l2_buf.index; + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + if (temp_vb->b->v4l2_planes[0].bytesused == 0) { + last_frame = 1; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v6(ctx, last_frame); + + return 0; +} + +static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + /* + unsigned int src_y_size, src_c_size; + */ + unsigned int dst_size; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "no src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + src_mb->flags |= MFC_BUF_FLAG_USED; + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); + + mfc_debug(2, "enc src y addr: 0x%08lx", src_y_addr); + mfc_debug(2, "enc src c addr: 0x%08lx", src_c_addr); + + s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + + spin_unlock_irqrestore(&dev->irqlock, flags); + + index = src_mb->b->v4l2_buf.index; + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_encode_one_frame_v6(ctx); + + return 0; +} + +static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + spin_lock_irqsave(&dev->irqlock, flags); + mfc_debug(2, "Preparing to init decoding.\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_decode_v6(ctx); +} + +static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + spin_lock_irqsave(&dev->irqlock, flags); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_encode_v6(ctx); +} + +static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + /* Header was parsed now start processing + * First set the output frame buffers + * s5p_mfc_alloc_dec_buffers(ctx); */ + + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destionation buffers were\n" + "mmaped.MFC requires that all destination are mmaped\n" + "before starting processing.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + ret = s5p_mfc_alloc_codec_buffers_v6(ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers.\n"); + return -ENOMEM; + } + + /* Header was generated now starting processing + * First set the reference frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_REQUESTED) { + mfc_err("It seems that destionation buffers were not\n" + "requested.MFC requires that header should be generated\n" + "before allocating codec buffer.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + mfc_debug(1, "Try run dev: %p\n", dev); + + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW.\n"); + return; + } + + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware.\n"); + return; + } + + mfc_debug(1, "No ctx is scheduled to be run.\n"); + return; + } + + mfc_debug(1, "New context: %d\n", new_ctx); + ctx = dev->ctx[new_ctx]; + mfc_debug(1, "Seting new context to %p\n", ctx); + /* Got context to run in ctx */ + mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", + ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt); + mfc_debug(1, "ctx->state=%d\n", ctx->state); + /* Last frame has already been sent to MFC + * Now obtaining frames from MFC buffer */ + + s5p_mfc_clock_on(); + if (ctx->type == MFCINST_DECODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change.\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec`.\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + case MFCINST_HEAD_PARSED: /* Only for MFC6.x */ + ret = s5p_mfc_run_init_enc_buffers(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware.\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + + +void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->num_planes; i++) + vb2_set_plane_payload(b->b, i, 0); + vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + +void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6); +} + +void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_clock_on(); + WRITEL(data, ofs); + s5p_mfc_clock_off(); +} + +unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + s5p_mfc_clock_on(); + ret = READL(ofs); + s5p_mfc_clock_off(); + + return ret; +} + +int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); +} + +int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); +} + +int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6); +} + +int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6); +} + +int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) +{ + return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6); +} + +int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) & + S5P_FIMV_RISC2HOST_CMD_MASK; +} + +int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6); +} + +int s5p_mfc_err_dec_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; +} + +int s5p_mfc_err_dspl_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6; +} + +int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); +} + +int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); +} + +int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6); +} + +int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6); +} + +int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6); +} + +int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6); +} + +int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6); +} + +int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6); +} + +int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6); +} + +int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) +{ + return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); +} + +int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6); +} + +int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6); +} + +unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6); +} + +unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6); +} + +unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6); +} + +unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6); +} + +/* Initialize opr function pointers for MFC v6 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v6, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v6, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v6, + .alloc_dev_context_buffer = + s5p_mfc_alloc_dev_context_buffer_v6, + .release_dev_context_buffer = + s5p_mfc_release_dev_context_buffer_v6, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, + .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6, + .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, + .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6, + .init_decode = s5p_mfc_init_decode_v6, + .init_encode = s5p_mfc_init_encode_v6, + .encode_one_frame = s5p_mfc_encode_one_frame_v6, + .try_run = s5p_mfc_try_run_v6, + .cleanup_queue = s5p_mfc_cleanup_queue_v6, + .clear_int_flags = s5p_mfc_clear_int_flags_v6, + .write_info = s5p_mfc_write_info_v6, + .read_info = s5p_mfc_read_info_v6, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, + .get_dspl_status = s5p_mfc_get_dspl_status_v6, + .get_dec_status = s5p_mfc_get_dec_status_v6, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v6, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v6, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v6, + .get_int_reason = s5p_mfc_get_int_reason_v6, + .get_int_err = s5p_mfc_get_int_err_v6, + .err_dec = s5p_mfc_err_dec_v6, + .err_dspl = s5p_mfc_err_dspl_v6, + .get_img_width = s5p_mfc_get_img_width_v6, + .get_img_height = s5p_mfc_get_img_height_v6, + .get_dpb_count = s5p_mfc_get_dpb_count_v6, + .get_mv_count = s5p_mfc_get_mv_count_v6, + .get_inst_no = s5p_mfc_get_inst_no_v6, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, + .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6, + .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6, + .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6, + .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) +{ + return &s5p_mfc_ops_v6; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h new file mode 100644 index 000000000000..ab164efa127e --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -0,0 +1,50 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef S5P_MFC_OPR_V6_H_ +#define S5P_MFC_OPR_V6_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" + +#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR + +#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16) +#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) +#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) + +/* Definition */ +#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) +#define ENC_MULTI_SLICE_BIT_MIN 2800 +#define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1) +#define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1) +#define ENC_H264_LOOP_FILTER_AB_MIN -12 +#define ENC_H264_LOOP_FILTER_AB_MAX 12 +#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H264_PROFILE_MAX 3 +#define ENC_H264_LEVEL_MAX 42 +#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) +#define FRAME_DELTA_H264_H263 1 +#define TIGHT_CBR_MAX 10 + +/* Definitions for shared memory compatibility */ +#define PIC_TIME_TOP_V6 S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 +#define PIC_TIME_BOT_V6 S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 +#define CROP_INFO_H_V6 S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 +#define CROP_INFO_V_V6 S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); +#endif /* S5P_MFC_OPR_V6_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 0503d14ac94e..367db7552289 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -20,7 +20,6 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" -#define MFC_CLKNAME "sclk_mfc" #define MFC_GATE_CLK_NAME "mfc" #define CLK_DEBUG @@ -51,7 +50,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) goto err_p_ip_clk; } - pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); + pm->clock = clk_get(&dev->plat_dev->dev, dev->variant->mclk_name); if (IS_ERR(pm->clock)) { mfc_err("Failed to get MFC clock\n"); ret = PTR_ERR(pm->clock); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c deleted file mode 100644 index b5933d233a4b..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifdef CONFIG_ARCH_EXYNOS4 -#include <linux/dma-mapping.h> -#endif -#include <linux/io.h> -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" - -int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; - - ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx, - SHARED_BUF_SIZE); - if (IS_ERR(ctx->shm_alloc)) { - mfc_err("failed to allocate shared memory\n"); - return PTR_ERR(ctx->shm_alloc); - } - /* shm_ofs only keeps the offset from base (port a) */ - ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc) - - dev->bank1; - BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc); - if (!ctx->shm) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_ofs = 0; - ctx->shm_alloc = NULL; - mfc_err("failed to virt addr of shared memory\n"); - return -ENOMEM; - } - memset((void *)ctx->shm, 0, SHARED_BUF_SIZE); - wmb(); - return 0; -} - diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 403d7f17bfab..9fd9d1c5b218 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1376,6 +1376,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, __u32 pixfmt = pix->pixelformat; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_fmt_cfg *emma_prp; unsigned int width_limit; int ret; @@ -1438,12 +1439,11 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, __func__, pcdev->s_width, pcdev->s_height); /* If the sensor does not support image size try PrP resizing */ - pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, + emma_prp = mx27_emma_prp_get_format(xlate->code, xlate->host_fmt->fourcc); - memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); if ((mf.width != pix->width || mf.height != pix->height) && - pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { + emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } @@ -1655,6 +1655,7 @@ static int __devinit mx27_camera_emma_init(struct platform_device *pdev) irq_emma = platform_get_irq(pdev, 1); if (!res_emma || !irq_emma) { dev_err(pcdev->dev, "no EMMA resources\n"); + err = -ENODEV; goto out; } diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 3be92944f8e7..d3f0b84e2d70 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -950,11 +950,11 @@ static int soc_camera_s_selection(struct file *file, void *fh, /* In all these cases cropping emulation will not help */ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - (s->target != V4L2_SEL_TGT_COMPOSE_ACTIVE && - s->target != V4L2_SEL_TGT_CROP_ACTIVE)) + (s->target != V4L2_SEL_TGT_COMPOSE && + s->target != V4L2_SEL_TGT_CROP)) return -EINVAL; - if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + if (s->target == V4L2_SEL_TGT_COMPOSE) { /* No output size change during a running capture! */ if (is_streaming(ici, icd) && (icd->user_width != s->r.width || @@ -974,7 +974,7 @@ static int soc_camera_s_selection(struct file *file, void *fh, ret = ici->ops->set_selection(icd, s); if (!ret && - s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + s->target == V4L2_SEL_TGT_COMPOSE) { icd->user_width = s->r.width; icd->user_height = s->r.height; if (!icd->streamer) @@ -1184,7 +1184,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) sd->grp_id = soc_camera_grp_id(icd); v4l2_set_subdev_hostdata(sd, icd); - if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL)) + ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL); + if (ret < 0) goto ectrl; /* At this point client .probe() should have run already */ @@ -1529,12 +1530,11 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) { struct soc_camera_link *icl = pdev->dev.platform_data; struct soc_camera_device *icd; - int ret; if (!icl) return -EINVAL; - icd = kzalloc(sizeof(*icd), GFP_KERNEL); + icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL); if (!icd) return -ENOMEM; @@ -1543,19 +1543,10 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) icd->pdev = &pdev->dev; platform_set_drvdata(pdev, icd); - ret = soc_camera_device_register(icd); - if (ret < 0) - goto escdevreg; - icd->user_width = DEFAULT_WIDTH; icd->user_height = DEFAULT_HEIGHT; - return 0; - -escdevreg: - kfree(icd); - - return ret; + return soc_camera_device_register(icd); } /* @@ -1572,8 +1563,6 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) list_del(&icd->list); - kfree(icd); - return 0; } @@ -1586,18 +1575,7 @@ static struct platform_driver __refdata soc_camera_pdrv = { }, }; -static int __init soc_camera_init(void) -{ - return platform_driver_register(&soc_camera_pdrv); -} - -static void __exit soc_camera_exit(void) -{ - platform_driver_unregister(&soc_camera_pdrv); -} - -module_init(soc_camera_init); -module_exit(soc_camera_exit); +module_platform_driver(soc_camera_pdrv); MODULE_DESCRIPTION("Image capture bus driver"); MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index e5024cfd27a7..4ef55ec8045e 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -308,7 +308,7 @@ static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) READCHAN_BLERD) >> 10; rds = radio->registers[RDSD]; break; - }; + } /* Fill the V4L2 RDS buffer */ put_unaligned_le16(rds, &tmpbuf); diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index be076f7181e7..62f3edec39bc 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -446,7 +446,7 @@ static void si470x_int_in_callback(struct urb *urb) READCHAN_BLERD) >> 10; rds = radio->registers[RDSD]; break; - }; + } /* Fill the V4L2 RDS buffer */ put_unaligned_le16(rds, &tmpbuf); diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index a9e6d17015ef..e3079c142c5f 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1009,7 +1009,7 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, default: rval = -EINVAL; - }; + } return rval; } @@ -1081,7 +1081,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, default: rval = -EINVAL; break; - }; + } exit: return rval; @@ -1130,7 +1130,7 @@ static int si4713_write_econtrol_tune(struct si4713_device *sdev, default: rval = -EINVAL; goto unlock; - }; + } if (sdev->power_state) rval = si4713_tx_tune_power(sdev, power, antcap); @@ -1420,7 +1420,7 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev, default: rval = -EINVAL; break; - }; + } exit: return rval; @@ -1473,7 +1473,7 @@ static int si4713_read_econtrol_tune(struct si4713_device *sdev, break; default: rval = -EINVAL; - }; + } unlock: mutex_unlock(&sdev->mutex); @@ -1698,7 +1698,7 @@ static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) default: rval = -EINVAL; break; - }; + } return rval; } diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 647dd951b0e8..d05ac15b5de4 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -881,10 +881,13 @@ static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask) static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier) { struct ene_device *dev = rdev->priv; - u32 period = 2000000 / carrier; + u32 period; dbg("TX: attempt to set tx carrier to %d kHz", carrier); + if (carrier == 0) + return -EINVAL; + period = 2000000 / carrier; if (period && (period > ENE_CIRMOD_PRD_MAX || period < ENE_CIRMOD_PRD_MIN)) { diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 1e4c68a5cecf..51d7057aca04 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -28,6 +28,7 @@ #include <media/rc-core.h> #define DRIVER_NAME "iguanair" +#define BUF_SIZE 152 struct iguanair { struct rc_dev *rc; @@ -35,26 +36,23 @@ struct iguanair { struct device *dev; struct usb_device *udev; - int pipe_out; uint16_t version; uint8_t bufsize; + uint8_t cycle_overhead; struct mutex lock; /* receiver support */ bool receiver_on; - dma_addr_t dma_in; + dma_addr_t dma_in, dma_out; uint8_t *buf_in; - struct urb *urb_in; + struct urb *urb_in, *urb_out; struct completion completion; /* transmit support */ bool tx_overflow; uint32_t carrier; - uint8_t cycle_overhead; - uint8_t channels; - uint8_t busy4; - uint8_t busy7; + struct send_packet *packet; char name[64]; char phys[64]; @@ -73,7 +71,8 @@ struct iguanair { #define DIR_IN 0xdc #define DIR_OUT 0xcd -#define MAX_PACKET_SIZE 8u +#define MAX_IN_PACKET 8u +#define MAX_OUT_PACKET (sizeof(struct send_packet) + BUF_SIZE) #define TIMEOUT 1000 #define RX_RESOLUTION 21333 @@ -191,20 +190,25 @@ static void iguanair_rx(struct urb *urb) dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc); } -static int iguanair_send(struct iguanair *ir, void *data, unsigned size) +static void iguanair_irq_out(struct urb *urb) { - int rc, transferred; + struct iguanair *ir = urb->context; + + if (urb->status) + dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status); +} + +static int iguanair_send(struct iguanair *ir, unsigned size) +{ + int rc; INIT_COMPLETION(ir->completion); - rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size, - &transferred, TIMEOUT); + ir->urb_out->transfer_buffer_length = size; + rc = usb_submit_urb(ir->urb_out, GFP_KERNEL); if (rc) return rc; - if (transferred != size) - return -EIO; - if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0) return -ETIMEDOUT; @@ -213,14 +217,13 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size) static int iguanair_get_features(struct iguanair *ir) { - struct packet packet; int rc; - packet.start = 0; - packet.direction = DIR_OUT; - packet.cmd = CMD_GET_VERSION; + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = CMD_GET_VERSION; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get version\n"); goto out; @@ -235,17 +238,23 @@ static int iguanair_get_features(struct iguanair *ir) ir->bufsize = 150; ir->cycle_overhead = 65; - packet.cmd = CMD_GET_BUFSIZE; + ir->packet->header.cmd = CMD_GET_BUFSIZE; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get buffer size\n"); goto out; } - packet.cmd = CMD_GET_FEATURES; + if (ir->bufsize > BUF_SIZE) { + dev_info(ir->dev, "buffer size %u larger than expected\n", + ir->bufsize); + ir->bufsize = BUF_SIZE; + } + + ir->packet->header.cmd = CMD_GET_FEATURES; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get features\n"); goto out; @@ -257,13 +266,18 @@ out: static int iguanair_receiver(struct iguanair *ir, bool enable) { - struct packet packet = { 0, DIR_OUT, enable ? - CMD_RECEIVER_ON : CMD_RECEIVER_OFF }; + int rc; + + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; if (enable) ir_raw_event_reset(ir->rc); - return iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); + + return rc; } /* @@ -308,8 +322,8 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) fours = (cycles - sevens * 7) / 4; /* magic happens here */ - ir->busy7 = (4 - sevens) * 2; - ir->busy4 = 110 - fours; + ir->packet->busy7 = (4 - sevens) * 2; + ir->packet->busy4 = 110 - fours; } mutex_unlock(&ir->lock); @@ -325,7 +339,7 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask) return 4; mutex_lock(&ir->lock); - ir->channels = mask; + ir->packet->channels = mask << 4; mutex_unlock(&ir->lock); return 0; @@ -337,16 +351,9 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) uint8_t space; unsigned i, size, periods, bytes; int rc; - struct send_packet *packet; mutex_lock(&ir->lock); - packet = kmalloc(sizeof(*packet) + ir->bufsize, GFP_KERNEL); - if (!packet) { - rc = -ENOMEM; - goto out; - } - /* convert from us to carrier periods */ for (i = space = size = 0; i < count; i++) { periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); @@ -356,11 +363,11 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) break; } while (periods > 127) { - packet->payload[size++] = 127 | space; + ir->packet->payload[size++] = 127 | space; periods -= 127; } - packet->payload[size++] = periods | space; + ir->packet->payload[size++] = periods | space; space ^= 0x80; } @@ -369,36 +376,19 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) goto out; } - packet->header.start = 0; - packet->header.direction = DIR_OUT; - packet->header.cmd = CMD_SEND; - packet->length = size; - packet->channels = ir->channels << 4; - packet->busy7 = ir->busy7; - packet->busy4 = ir->busy4; - - if (ir->receiver_on) { - rc = iguanair_receiver(ir, false); - if (rc) { - dev_warn(ir->dev, "disable receiver before transmit failed\n"); - goto out; - } - } + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = CMD_SEND; + ir->packet->length = size; ir->tx_overflow = false; - rc = iguanair_send(ir, packet, size + 8); + rc = iguanair_send(ir, sizeof(*ir->packet) + size); if (rc == 0 && ir->tx_overflow) rc = -EOVERFLOW; - if (ir->receiver_on) { - if (iguanair_receiver(ir, true)) - dev_warn(ir->dev, "re-enable receiver after transmit failed\n"); - } - out: - kfree(packet); mutex_unlock(&ir->lock); return rc ? rc : count; @@ -411,8 +401,6 @@ static int iguanair_open(struct rc_dev *rdev) mutex_lock(&ir->lock); - BUG_ON(ir->receiver_on); - rc = iguanair_receiver(ir, true); if (rc == 0) ir->receiver_on = true; @@ -443,7 +431,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf, struct usb_device *udev = interface_to_usbdev(intf); struct iguanair *ir; struct rc_dev *rc; - int ret, pipein; + int ret, pipein, pipeout; struct usb_host_interface *idesc; ir = kzalloc(sizeof(*ir), GFP_KERNEL); @@ -453,11 +441,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, goto out; } - ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL, + ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL, &ir->dma_in); + ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL, + &ir->dma_out); ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); + ir->urb_out = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->buf_in || !ir->urb_in) { + if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) { ret = -ENOMEM; goto out; } @@ -472,13 +463,18 @@ static int __devinit iguanair_probe(struct usb_interface *intf, ir->rc = rc; ir->dev = &intf->dev; ir->udev = udev; - ir->pipe_out = usb_sndintpipe(udev, - idesc->endpoint[1].desc.bEndpointAddress); mutex_init(&ir->lock); + init_completion(&ir->completion); + pipeout = usb_sndintpipe(udev, + idesc->endpoint[1].desc.bEndpointAddress); + usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET, + iguanair_irq_out, ir, 1); + ir->urb_out->transfer_dma = ir->dma_out; + ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress); - usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE, + usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET, iguanair_rx, ir, 1); ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -528,11 +524,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, return 0; out2: usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); out: if (ir) { usb_free_urb(ir->urb_in); - usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in, - ir->dma_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); + usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet, + ir->dma_out); } rc_free_device(rc); kfree(ir); @@ -546,8 +545,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf) rc_unregister_device(ir->rc); usb_set_intfdata(intf, NULL); usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); usb_free_urb(ir->urb_in); - usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); + usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out); kfree(ir); } @@ -565,6 +567,7 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message) } usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); mutex_unlock(&ir->lock); diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 569124b03de3..870c93052fd0 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -203,13 +203,13 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, /* TX settings */ case LIRC_SET_TRANSMITTER_MASK: if (!dev->s_tx_mask) - return -EINVAL; + return -ENOSYS; return dev->s_tx_mask(dev, val); case LIRC_SET_SEND_CARRIER: if (!dev->s_tx_carrier) - return -EINVAL; + return -ENOSYS; return dev->s_tx_carrier(dev, val); diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index c64e9e30045d..2fa71d0d72d7 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -22,24 +22,24 @@ #include <linux/module.h> static struct rc_map_table msi_digivox_ii[] = { - { 0x0002, KEY_2 }, - { 0x0003, KEY_UP }, /* up */ - { 0x0004, KEY_3 }, - { 0x0005, KEY_CHANNELDOWN }, - { 0x0008, KEY_5 }, - { 0x0009, KEY_0 }, - { 0x000b, KEY_8 }, - { 0x000d, KEY_DOWN }, /* down */ - { 0x0010, KEY_9 }, - { 0x0011, KEY_7 }, - { 0x0014, KEY_VOLUMEUP }, - { 0x0015, KEY_CHANNELUP }, - { 0x0016, KEY_OK }, - { 0x0017, KEY_POWER2 }, - { 0x001a, KEY_1 }, - { 0x001c, KEY_4 }, - { 0x001d, KEY_6 }, - { 0x001f, KEY_VOLUMEDOWN }, + { 0x0302, KEY_2 }, + { 0x0303, KEY_UP }, /* up */ + { 0x0304, KEY_3 }, + { 0x0305, KEY_CHANNELDOWN }, + { 0x0308, KEY_5 }, + { 0x0309, KEY_0 }, + { 0x030b, KEY_8 }, + { 0x030d, KEY_DOWN }, /* down */ + { 0x0310, KEY_9 }, + { 0x0311, KEY_7 }, + { 0x0314, KEY_VOLUMEUP }, + { 0x0315, KEY_CHANNELUP }, + { 0x0316, KEY_OK }, + { 0x0317, KEY_POWER2 }, + { 0x031a, KEY_1 }, + { 0x031c, KEY_4 }, + { 0x031d, KEY_6 }, + { 0x031f, KEY_VOLUMEDOWN }, }; static struct rc_map_list msi_digivox_ii_map = { diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 699eef39128b..2ea913a44ae8 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -517,6 +517,9 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) struct nvt_dev *nvt = dev->priv; u16 val; + if (carrier == 0) + return -EINVAL; + nvt_cir_reg_write(nvt, 1, CIR_CP); val = 3000000 / (carrier) - 1; nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 49731b1a9c57..9f5a17bb5ef5 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -890,6 +890,9 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) struct device *dev = rr3->dev; rr3_dbg(dev, "Setting modulation frequency to %u", carrier); + if (carrier == 0) + return -EINVAL; + rr3->carrier = carrier; return carrier; diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 30ae1f24abc3..7c9b5f33113b 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -184,7 +184,7 @@ enum wbcir_txstate { }; /* Misc */ -#define WBCIR_NAME "Winbond CIR" +#define WBCIR_NAME "winbond-cir" #define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ #define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ #define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 0ed9091ff48e..2e1a02e360ff 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -245,7 +245,7 @@ struct mt2063_state { /* * mt2063_write - Write data into the I2C bus */ -static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) +static int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) { struct dvb_frontend *fe = state->frontend; int ret; @@ -277,9 +277,9 @@ static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) /* * mt2063_write - Write register data into the I2C bus, caching the value */ -static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) +static int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) { - u32 status; + int status; dprintk(2, "\n"); @@ -298,10 +298,10 @@ static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) /* * mt2063_read - Read data from the I2C bus */ -static u32 mt2063_read(struct mt2063_state *state, +static int mt2063_read(struct mt2063_state *state, u8 subAddress, u8 *pData, u32 cnt) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ struct dvb_frontend *fe = state->frontend; u32 i = 0; @@ -816,7 +816,7 @@ static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, */ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) { - u32 status = 0; + int status = 0; u32 fm, fp; /* restricted range on LO's */ pAS_Info->bSpurAvoided = 0; pAS_Info->nSpursFound = 0; @@ -935,14 +935,14 @@ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) * * This function returns 0, if no lock, 1 if locked and a value < 1 if error */ -static unsigned int mt2063_lockStatus(struct mt2063_state *state) +static int mt2063_lockStatus(struct mt2063_state *state) { const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ const u32 nPollRate = 2; /* poll status bits every 2 ms */ const u32 nMaxLoops = nMaxWait / nPollRate; const u8 LO1LK = 0x80; u8 LO2LK = 0x08; - u32 status; + int status; u32 nDelays = 0; dprintk(2, "\n"); @@ -1069,7 +1069,7 @@ static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, enum MT2063_DNC_Output_Enable nValue) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ u8 val = 0; dprintk(2, "\n"); @@ -1203,7 +1203,7 @@ static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, static u32 MT2063_SetReceiverMode(struct mt2063_state *state, enum mt2063_delivery_sys Mode) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ u8 val; u32 longval; @@ -1345,7 +1345,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits) { - u32 status = 0; + int status = 0; dprintk(2, "\n"); Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ @@ -1374,7 +1374,7 @@ static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, */ static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) { - u32 status; + int status; dprintk(2, "\n"); if (Shutdown == 1) @@ -1540,7 +1540,7 @@ static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) { /* RF input center frequency */ - u32 status = 0; + int status = 0; u32 LO1; /* 1st LO register value */ u32 Num1; /* Numerator for LO1 reg. value */ u32 f_IF1; /* 1st IF requested */ @@ -1803,7 +1803,7 @@ static const u8 MT2063B3_defaults[] = { static int mt2063_init(struct dvb_frontend *fe) { - u32 status; + int status; struct mt2063_state *state = fe->tuner_priv; u8 all_resets = 0xF0; /* reset/load bits */ const u8 *def = NULL; @@ -2249,8 +2249,8 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, dprintk(2, "\n"); state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -2261,18 +2261,15 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, printk(KERN_INFO "%s: Attaching MT2063\n", __func__); return fe; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL_GPL(mt2063_attach); +#if 0 /* * Ancillary routines visible outside mt2063 * FIXME: Remove them in favor of using standard tuner callbacks */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) +static int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; @@ -2285,9 +2282,8 @@ unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) return err; } -EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) +static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; @@ -2300,7 +2296,7 @@ unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) return err; } -EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); +#endif MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); MODULE_DESCRIPTION("MT2063 Silicon tuner"); diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h index 3f5cfd93713f..ab24170c1571 100644 --- a/drivers/media/tuners/mt2063.h +++ b/drivers/media/tuners/mt2063.h @@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, return NULL; } -/* FIXME: Should use the standard DVB attachment interfaces */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); - #endif /* CONFIG_DVB_MT2063 */ #endif /* __MT2063_H__ */ diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 221171eeb0c3..18c77afe2e4f 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -187,7 +187,8 @@ int tda18271_read_extended(struct dvb_frontend *fe) return (ret == 2 ? 0 : ret); } -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -198,7 +199,6 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) BUG_ON((len == 0) || (idx + len > sizeof(buf))); - switch (priv->small_i2c) { case TDA18271_03_BYTE_CHUNK_INIT: max = 3; @@ -214,7 +214,19 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) max = 39; } - tda18271_i2c_gate_ctrl(fe, 1); + + /* + * If lock_i2c is true, it will take the I2C bus for tda18271 private + * usage during the entire write ops, as otherwise, bad things could + * happen. + * During device init, several write operations will happen. So, + * tda18271_init_regs controls the I2C lock directly, + * disabling lock_i2c here. + */ + if (lock_i2c) { + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + } while (len) { if (max > len) max = len; @@ -226,14 +238,17 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) msg.len = max + 1; /* write registers */ - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + ret = __i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) break; idx += max; len -= max; } - tda18271_i2c_gate_ctrl(fe, 0); + if (lock_i2c) { + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); + } if (ret != 1) tda_err("ERROR: idx = 0x%x, len = %d, " @@ -242,10 +257,16 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) return (ret == 1 ? 0 : ret); } +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + return __tda18271_write_regs(fe, idx, len, true); +} + /*---------------------------------------------------------------------*/ -int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force) +static int __tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -255,9 +276,16 @@ int tda18271_charge_pump_source(struct dvb_frontend *fe, regs[r_cp] &= ~0x20; regs[r_cp] |= ((force & 1) << 5); - return tda18271_write_regs(fe, r_cp, 1); + return __tda18271_write_regs(fe, r_cp, 1, lock_i2c); +} + +int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force) +{ + return __tda18271_charge_pump_source(fe, pll, force, true); } + int tda18271_init_regs(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -267,6 +295,13 @@ int tda18271_init_regs(struct dvb_frontend *fe) i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); + /* + * Don't let any other I2C transfer to happen at adapter during init, + * as those could cause bad things + */ + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + /* initialize registers */ switch (priv->id) { case TDA18271HDC1: @@ -352,28 +387,28 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_EB22] = 0x48; regs[R_EB23] = 0xb0; - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + __tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS, false); /* setup agc1 gain */ regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); /* setup agc2 gain */ if ((priv->id) == TDA18271HDC1) { regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); } /* image rejection calibration */ @@ -391,21 +426,21 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD2] = 0x08; regs[R_MD3] = 0x00; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); if ((priv->id) == TDA18271HDC2) { /* main pll cp source on */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1, false); msleep(1); /* main pll cp source off */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0, false); } msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted low measurement */ regs[R_EP5] = 0x85; @@ -413,11 +448,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0x70; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image low optimization completion */ /* mid-band */ @@ -428,11 +463,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x73; regs[R_MD2] = 0x1a; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted mid measurement */ regs[R_EP5] = 0x86; @@ -440,11 +475,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0xa0; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image mid optimization completion */ /* high-band */ @@ -456,30 +491,33 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x71; regs[R_MD2] = 0xcd; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted high measurement */ regs[R_EP5] = 0x87; regs[R_CD1] = 0x65; regs[R_CD2] = 0x50; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image high optimization completion */ /* return to normal mode */ regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); + __tda18271_write_regs(fe, R_EP4, 1, false); /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); + + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); return 0; } diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 824f1911ee21..3d7526e28d42 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -500,7 +500,7 @@ static int af9015_read_config(struct dvb_usb_device *d) case 3: state->af9013_config[i].clock = 25000000; break; - }; + } dev_dbg(&d->udev->dev, "%s: [%d] xtal=%d set clock=%d\n", __func__, i, val, state->af9013_config[i].clock); @@ -568,7 +568,7 @@ static int af9015_read_config(struct dvb_usb_device *d) "supported, please report!\n", KBUILD_MODNAME, val); return -ENODEV; - }; + } state->af9013_config[i].tuner = val; dev_dbg(&d->udev->dev, "%s: [%d] tuner id=%d\n", diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index aabd3fc03ea7..ea27eaff4e34 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -520,7 +520,7 @@ static int af9035_read_config(struct dvb_usb_device *d) dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \ "supported, please report!", KBUILD_MODNAME, tmp); - }; + } /* tuner IF frequency */ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c index 8d7fef84afd8..83684ed023cd 100644 --- a/drivers/media/usb/dvb-usb/a800.c +++ b/drivers/media/usb/dvb-usb/a800.c @@ -93,7 +93,7 @@ static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) /* call the universal NEC remote processor, to find out the key's state and event */ dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_rc("key: %*ph\n", 5, key); ret = 0; out: kfree(key); diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 0a98548ecd17..9fd1527494eb 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -172,8 +172,7 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) if (*event != d->last_event) st->rc_counter = 0; - deb_rc("key: %x %x %x %x %x\n", - key[0], key[1], key[2], key[3], key[4]); + deb_rc("key: %*ph\n", 5, key); } return 0; } diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index a76bbb29ca36..af0d4321845b 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -473,7 +473,7 @@ int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_info("key: %*ph\n", 5, key); return 0; } EXPORT_SYMBOL(dibusb_rc_query); diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index ff34419a4c88..772bde3c5020 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -253,7 +253,7 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) } if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_rc("key: %*ph\n", 5, key); return 0; } diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index 66f205c112b2..c357fb3b0a88 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -84,7 +84,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_info("key: %*ph\n", 5, key); return 0; } diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 288af29a8bb7..661bb75be955 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -358,7 +358,7 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) goto done; - deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); + deb("%*ph\n", 4, read); if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) goto done; diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index acefaa89cc53..7a8c8c18590f 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -677,6 +677,7 @@ static struct usb_device_id technisat_usb2_id_table[] = { { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, { 0 } /* Terminating entry */ }; +MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table); /* device description */ static struct dvb_usb_device_properties technisat_usb2_devices = { diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index f7297ae76b48..16a84f9f46d8 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2203,7 +2203,7 @@ EXPORT_SYMBOL_GPL(em28xx_tuner_callback); static inline void em28xx_set_model(struct em28xx *dev) { - memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board)); + dev->board = em28xx_boards[dev->model]; /* Those are the default values for the majority of boards Use those values if not specified otherwise at boards entry diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 913e5227897a..13ae821949e9 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -574,18 +574,19 @@ static void pctv_520e_init(struct em28xx *dev) i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); }; -static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe, int val) +static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct em28xx *dev = fe->dvb->priv; #ifdef CONFIG_GPIOLIB struct em28xx_dvb *dvb = dev->dvb; int ret; unsigned long flags; - if (val) - flags = GPIOF_OUT_INIT_LOW; + if (c->lna == 1) + flags = GPIOF_OUT_INIT_HIGH; /* enable LNA */ else - flags = GPIOF_OUT_INIT_HIGH; + flags = GPIOF_OUT_INIT_LOW; /* disable LNA */ ret = gpio_request_one(dvb->lna_gpio, flags, NULL); if (ret) @@ -595,8 +596,8 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe, int val) return ret; #else - dev_warn(&dev->udev->dev, "%s: LNA control is disabled\n", - KBUILD_MODNAME); + dev_warn(&dev->udev->dev, "%s: LNA control is disabled (lna=%u)\n", + KBUILD_MODNAME, c->lna); return 0; #endif } diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index b62740846061..34a26e0cfe77 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -100,12 +100,21 @@ int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value) void stk1160_select_input(struct stk1160 *dev) { + int route; static const u8 gctrl[] = { - 0x98, 0x90, 0x88, 0x80 + 0x98, 0x90, 0x88, 0x80, 0x98 }; - if (dev->ctl_input < ARRAY_SIZE(gctrl)) + if (dev->ctl_input == STK1160_SVIDEO_INPUT) + route = SAA7115_SVIDEO3; + else + route = SAA7115_COMPOSITE0; + + if (dev->ctl_input < ARRAY_SIZE(gctrl)) { + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + route, 0, 0); stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]); + } } /* TODO: We should break this into pieces */ @@ -351,8 +360,6 @@ static int stk1160_probe(struct usb_interface *interface, /* i2c reset saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - 0, 0, 0); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); /* reset stk1160 to default values */ diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index fe6e857969ca..6694f9e2ca57 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -419,7 +419,12 @@ static int vidioc_enum_input(struct file *file, void *priv, if (i->index > STK1160_MAX_INPUT) return -EINVAL; - sprintf(i->name, "Composite%d", i->index); + /* S-Video special handling */ + if (i->index == STK1160_SVIDEO_INPUT) + sprintf(i->name, "S-Video"); + else + sprintf(i->name, "Composite%d", i->index); + i->type = V4L2_INPUT_TYPE_CAMERA; i->std = dev->vdev.tvnorms; return 0; diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 3feba0033f98..68c8707d36ab 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -46,7 +46,8 @@ #define STK1160_MIN_PKT_SIZE 3072 -#define STK1160_MAX_INPUT 3 +#define STK1160_MAX_INPUT 4 +#define STK1160_SVIDEO_INPUT 4 #define STK1160_I2C_TIMEOUT 100 diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 5577381b5bf0..18a91fae6bc1 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -122,21 +122,27 @@ static struct vb2_ops uvc_queue_qops = { .buf_finish = uvc_buffer_finish, }; -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted) { + int ret; + queue->queue.type = type; queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; queue->queue.drv_priv = queue; queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - vb2_queue_init(&queue->queue); + ret = vb2_queue_init(&queue->queue); + if (ret) + return ret; mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->irqqueue); queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; + + return 0; } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 1c15b4227bdb..57c3076a4625 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1755,7 +1755,9 @@ int uvc_video_init(struct uvc_streaming *stream) atomic_set(&stream->active, 0); /* Initialize the video buffers queue. */ - uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); + ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); + if (ret) + return ret; /* Alternate setting 0 should be the default, yet the XBox Live Vision * Cam (and possibly other devices) crash or otherwise misbehave if diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 3764040475bb..af216ec45e39 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -600,7 +600,7 @@ extern struct uvc_driver uvc_driver; extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -extern void uvc_queue_init(struct uvc_video_queue *queue, +extern int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted); extern int uvc_alloc_buffers(struct uvc_video_queue *queue, struct v4l2_requestbuffers *rb); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 631cdc0e0bda..f6ee201d9347 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -384,6 +384,25 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Extended SAR", NULL, }; + static const char * const h264_fp_arrangement_type[] = { + "Checkerboard", + "Column", + "Row", + "Side by Side", + "Top Bottom", + "Temporal", + NULL, + }; + static const char * const h264_fmo_map_type[] = { + "Interleaved Slices", + "Scattered Slices", + "Foreground with Leftover", + "Box Out", + "Raster Scan", + "Wipe Scan", + "Explicit", + NULL, + }; static const char * const mpeg_mpeg4_level[] = { "0", "0b", @@ -508,6 +527,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_profile; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return vui_sar_idc; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + return h264_fp_arrangement_type; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + return h264_fmo_map_type; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return mpeg_mpeg4_level; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: @@ -643,6 +666,22 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR"; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable"; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type"; + case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs"; + case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: + return "H264 Set QP Value for HC Layers"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -657,6 +696,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -749,6 +789,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls"; case V4L2_CID_LINK_FREQ: return "Link Frequency"; case V4L2_CID_PIXEL_RATE: return "Pixel Rate"; + case V4L2_CID_TEST_PATTERN: return "Test Pattern"; /* DV controls */ case V4L2_CID_DV_CLASS: return "Digital Video Controls"; @@ -853,6 +894,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: case V4L2_CID_MPEG_VIDEO_H264_PROFILE: case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: @@ -862,6 +905,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_TX_MODE: case V4L2_CID_DV_TX_RGB_RANGE: case V4L2_CID_DV_RX_RGB_RANGE: + case V4L2_CID_TEST_PATTERN: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: @@ -1648,6 +1692,36 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, } EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); +/* Helper function for standard menu controls with driver defined menu */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 mask, s32 def, const char * const *qmenu) +{ + enum v4l2_ctrl_type type; + const char *name; + u32 flags; + s32 step; + s32 min; + + /* v4l2_ctrl_new_std_menu_items() should only be called for + * standard controls without a standard menu. + */ + if (v4l2_ctrl_get_menu(id)) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, id, name, type, 0, max, mask, def, + flags, qmenu, NULL, NULL); + +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items); + /* Helper function for standard integer menu controls */ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 9d3e46c446ad..8f388ff31ebb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -157,8 +157,7 @@ static const char *v4l2_memory_names[] = { [V4L2_MEMORY_OVERLAY] = "overlay", }; -#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ - arr[a] : "unknown") +#define prt_names(a, arr) (((unsigned)(a)) < ARRAY_SIZE(arr) ? arr[a] : "unknown") /* ------------------------------------------------------------------ */ /* debug help functions */ @@ -2188,6 +2187,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, int ret = 0; switch (cmd) { + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: { @@ -2211,6 +2211,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, struct v4l2_subdev_edid *edid = parg; if (edid->blocks) { + if (edid->blocks > 256) { + ret = -EINVAL; + break; + } *user_ptr = (void __user *)edid->edid; *kernel_ptr = (void *)&edid->edid; *array_size = edid->blocks * 128; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index e6a26b433e87..432df119af27 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -276,6 +276,9 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) */ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) { + if (!V4L2_TYPE_IS_MULTIPLANAR(b->type)) + return 0; + /* Is memory for copying plane information present? */ if (NULL == b->m.planes) { dprintk(1, "Multi-planar buffer passed but " @@ -331,10 +334,9 @@ static bool __buffers_in_use(struct vb2_queue *q) * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */ -static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) +static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - int ret; /* Copy back data such as timestamp, flags, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); @@ -342,14 +344,11 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->reserved = vb->v4l2_buf.reserved; if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - /* * Fill in plane-related data if userspace provided an array - * for it. The memory and size is verified above. + * for it. The caller has already verified memory and size. */ + b->length = vb->num_planes; memcpy(b->m.planes, vb->v4l2_planes, b->length * sizeof(struct v4l2_plane)); } else { @@ -391,8 +390,6 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) if (__buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - - return 0; } /** @@ -411,6 +408,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; + int ret; if (b->type != q->type) { dprintk(1, "querybuf: wrong buffer type\n"); @@ -422,8 +420,10 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) return -EINVAL; } vb = q->bufs[b->index]; - - return __fill_v4l2_buffer(vb, b); + ret = __verify_planes_array(vb, b); + if (!ret) + __fill_v4l2_buffer(vb, b); + return ret; } EXPORT_SYMBOL(vb2_querybuf); @@ -813,24 +813,16 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) EXPORT_SYMBOL_GPL(vb2_buffer_done); /** - * __fill_vb2_buffer() - fill a vb2_buffer with information provided in - * a v4l2_buffer by the userspace + * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a + * v4l2_buffer by the userspace. The caller has already verified that struct + * v4l2_buffer has a valid number of planes. */ -static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, +static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, struct v4l2_plane *v4l2_planes) { unsigned int plane; - int ret; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { - /* - * Verify that the userspace gave us a valid array for - * plane information. - */ - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - /* Fill in driver-provided information for OUTPUT types */ if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* @@ -872,8 +864,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; - - return 0; } /** @@ -888,10 +878,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); - /* Verify and copy relevant information provided by the userspace */ - ret = __fill_vb2_buffer(vb, b, planes); - if (ret) - return ret; + /* Copy relevant information provided by the userspace */ + __fill_vb2_buffer(vb, b, planes); for (plane = 0; plane < vb->num_planes; ++plane) { /* Skip the plane if already verified */ @@ -966,7 +954,8 @@ err: */ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { - return __fill_vb2_buffer(vb, b, vb->v4l2_planes); + __fill_vb2_buffer(vb, b, vb->v4l2_planes); + return 0; } /** @@ -1059,7 +1048,9 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); return -EINVAL; } - + ret = __verify_planes_array(vb, b); + if (ret < 0) + return ret; ret = __buf_prepare(vb, b); if (ret < 0) return ret; @@ -1147,6 +1138,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) ret = -EINVAL; goto unlock; } + ret = __verify_planes_array(vb, b); + if (ret) + goto unlock; switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: @@ -1243,8 +1237,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * the locks or return an error if one occurred. */ call_qop(q, wait_finish, q); - if (ret) + if (ret) { + dprintk(1, "Sleep was interrupted\n"); return ret; + } } return 0; } @@ -1255,7 +1251,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * Will sleep if required for nonblocking == false. */ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, - int nonblocking) + struct v4l2_buffer *b, int nonblocking) { unsigned long flags; int ret; @@ -1273,10 +1269,16 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, */ spin_lock_irqsave(&q->done_lock, flags); *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); - list_del(&(*vb)->done_entry); + /* + * Only remove the buffer from done_list if v4l2_buffer can handle all + * the planes. + */ + ret = __verify_planes_array(*vb, b); + if (!ret) + list_del(&(*vb)->done_entry); spin_unlock_irqrestore(&q->done_lock, flags); - return 0; + return ret; } /** @@ -1335,12 +1337,9 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) dprintk(1, "dqbuf: invalid buffer type\n"); return -EINVAL; } - - ret = __vb2_get_done_vb(q, &vb, nonblocking); - if (ret < 0) { - dprintk(1, "dqbuf: error getting next done buffer\n"); + ret = __vb2_get_done_vb(q, &vb, b, nonblocking); + if (ret < 0) return ret; - } ret = call_qop(q, buf_finish, vb); if (ret) { diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 84e8d0c59ee5..f9eb91623701 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -27,7 +27,6 @@ #include <asm/gpio.h> -#include <mach/gpio-tegra.h> #include <linux/platform_data/mmc-sdhci-tegra.h> #include "sdhci-pltfm.h" diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index cb3356c9af80..04668b47a1df 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -175,13 +175,13 @@ struct e1000_info; /* * in the case of WTHRESH, it appears at least the 82571/2 hardware * writes back 4 descriptors when WTHRESH=5, and 3 descriptors when - * WTHRESH=4, and since we want 64 bytes at a time written back, set - * it to 5 + * WTHRESH=4, so a setting of 5 gives the most efficient bus + * utilization but to avoid possible Tx stalls, set it to 1 */ #define E1000_TXDCTL_DMA_BURST_ENABLE \ (E1000_TXDCTL_GRAN | /* set descriptor granularity */ \ E1000_TXDCTL_COUNT_DESC | \ - (5 << 16) | /* wthresh must be +1 more than desired */\ + (1 << 16) | /* wthresh must be +1 more than desired */\ (1 << 8) | /* hthresh */ \ 0x1f) /* pthresh */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index de57a2ba6bde..f444eb0b76d8 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2831,7 +2831,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) * set up some performance related parameters to encourage the * hardware to use the bus more efficiently in bursts, depends * on the tx_int_delay to be enabled, - * wthresh = 5 ==> burst write a cacheline (64 bytes) at a time + * wthresh = 1 ==> burst write is disabled to avoid Tx stalls * hthresh = 1 ==> prefetch when one or more available * pthresh = 0x1f ==> prefetch if internal cache 31 or less * BEWARE: this seems to work but should be considered first if diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index c911d883c27e..f8064df10cc4 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -2973,6 +2974,9 @@ jme_init_one(struct pci_dev *pdev, /* * set up PCI device basics */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + rc = pci_enable_device(pdev); if (rc) { pr_err("Cannot enable PCI device\n"); diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 434d5af8e6fb..c81e278629ff 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -244,8 +244,12 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) * - suspend: peripheral ready to suspend * - response: suggest N millisec polling * - response complete: suggest N sec polling + * + * Suspend is reported and maybe heeded. */ case 2: /* Suspend hint */ + usbnet_device_suggests_idle(dev); + continue; case 3: /* Response hint */ case 4: /* Response complete hint */ continue; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index c75e11e1b385..afb117c16d2d 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -424,7 +424,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, netdev_dbg(kaweth->net, "Downloading firmware at %p to kaweth device at %p\n", - fw->data, kaweth); + kaweth->firmware_buf, kaweth); netdev_dbg(kaweth->net, "Firmware length: %d\n", data_len); return kaweth_control(kaweth, diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 03c2d8d653df..cc7e72010ac3 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -117,6 +117,7 @@ enum { struct mcs7830_data { u8 multi_filter[8]; u8 config; + u8 link_counter; }; static const char driver_name[] = "MOSCHIP usb-ethernet driver"; @@ -632,20 +633,31 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) static void mcs7830_status(struct usbnet *dev, struct urb *urb) { u8 *buf = urb->transfer_buffer; - bool link; + bool link, link_changed; + struct mcs7830_data *data = mcs7830_get_data(dev); if (urb->actual_length < 16) return; link = !(buf[1] & 0x20); - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - } else - netif_carrier_off(dev->net); - netdev_dbg(dev->net, "Link Status is: %d\n", link); - } + link_changed = netif_carrier_ok(dev->net) != link; + if (link_changed) { + data->link_counter++; + /* + track link state 20 times to guard against erroneous + link state changes reported sometimes by the chip + */ + if (data->link_counter > 20) { + data->link_counter = 0; + if (link) { + netif_carrier_on(dev->net); + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + } else + netif_carrier_off(dev->net); + netdev_dbg(dev->net, "Link Status is: %d\n", link); + } + } else + data->link_counter = 0; } static const struct driver_info moschip_info = { diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index fc9f578a1e25..f9819d10b1f9 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1588,10 +1588,27 @@ int usbnet_resume (struct usb_interface *intf) tasklet_schedule (&dev->bh); } } + + if (test_and_clear_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) + usb_autopm_get_interface_no_resume(intf); + return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); +/* + * Either a subdriver implements manage_power, then it is assumed to always + * be ready to be suspended or it reports the readiness to be suspended + * explicitly + */ +void usbnet_device_suggests_idle(struct usbnet *dev) +{ + if (!test_and_set_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) { + dev->intf->needs_remote_wakeup = 1; + usb_autopm_put_interface_async(dev->intf); + } +} +EXPORT_SYMBOL(usbnet_device_suggests_idle); /*-------------------------------------------------------------------------*/ diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 8be9bf07bd39..607976c00162 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -106,6 +106,8 @@ struct vxlan_dev { __be32 gaddr; /* multicast group */ __be32 saddr; /* source address */ unsigned int link; /* link to multicast over */ + __u16 port_min; /* source port range */ + __u16 port_max; __u8 tos; /* TOS override */ __u8 ttl; bool learn; @@ -228,9 +230,9 @@ static u32 eth_hash(const unsigned char *addr) /* only want 6 bytes */ #ifdef __BIG_ENDIAN - value <<= 16; -#else value >>= 16; +#else + value <<= 16; #endif return hash_64(value, FDB_HASH_BITS); } @@ -535,7 +537,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) } __skb_pull(skb, sizeof(struct vxlanhdr)); - skb_postpull_rcsum(skb, eth_hdr(skb), sizeof(struct vxlanhdr)); /* Is this VNI defined? */ vni = ntohl(vxh->vx_vni) >> 8; @@ -554,7 +555,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) /* Re-examine inner Ethernet packet */ oip = ip_hdr(skb); skb->protocol = eth_type_trans(skb, vxlan->dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); /* Ignore packet loops (and multicast echo) */ if (compare_ether_addr(eth_hdr(skb)->h_source, @@ -566,6 +566,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) __skb_tunnel_rx(skb, vxlan->dev); skb_reset_network_header(skb); + skb->ip_summed = CHECKSUM_NONE; err = IP_ECN_decapsulate(oip, skb); if (unlikely(err)) { @@ -621,46 +622,89 @@ static inline u8 vxlan_ecn_encap(u8 tos, return INET_ECN_encapsulate(tos, inner); } +static __be32 vxlan_find_dst(struct vxlan_dev *vxlan, struct sk_buff *skb) +{ + const struct ethhdr *eth = (struct ethhdr *) skb->data; + const struct vxlan_fdb *f; + + if (is_multicast_ether_addr(eth->h_dest)) + return vxlan->gaddr; + + f = vxlan_find_mac(vxlan, eth->h_dest); + if (f) + return f->remote_ip; + else + return vxlan->gaddr; + +} + +static void vxlan_sock_free(struct sk_buff *skb) +{ + sock_put(skb->sk); +} + +/* On transmit, associate with the tunnel socket */ +static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) +{ + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); + struct sock *sk = vn->sock->sk; + + skb_orphan(skb); + sock_hold(sk); + skb->sk = sk; + skb->destructor = vxlan_sock_free; +} + +/* Compute source port for outgoing packet + * first choice to use L4 flow hash since it will spread + * better and maybe available from hardware + * secondary choice is to use jhash on the Ethernet header + */ +static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) +{ + unsigned int range = (vxlan->port_max - vxlan->port_min) + 1; + u32 hash; + + hash = skb_get_rxhash(skb); + if (!hash) + hash = jhash(skb->data, 2 * ETH_ALEN, + (__force u32) skb->protocol); + + return (((u64) hash * range) >> 32) + vxlan->port_min; +} + /* Transmit local packets over Vxlan * * Outer IP header inherits ECN and DF from inner header. * Outer UDP destination is the VXLAN assigned port. - * source port is based on hash of flow if available - * otherwise use a random value + * source port is based on hash of flow */ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); struct rtable *rt; - const struct ethhdr *eth; const struct iphdr *old_iph; struct iphdr *iph; struct vxlanhdr *vxh; struct udphdr *uh; struct flowi4 fl4; - struct vxlan_fdb *f; unsigned int pkt_len = skb->len; - u32 hash; __be32 dst; + __u16 src_port; __be16 df = 0; __u8 tos, ttl; int err; + dst = vxlan_find_dst(vxlan, skb); + if (!dst) + goto drop; + /* Need space for new headers (invalidates iph ptr) */ if (skb_cow_head(skb, VXLAN_HEADROOM)) goto drop; - eth = (void *)skb->data; old_iph = ip_hdr(skb); - if (!is_multicast_ether_addr(eth->h_dest) && - (f = vxlan_find_mac(vxlan, eth->h_dest))) - dst = f->remote_ip; - else if (vxlan->gaddr) { - dst = vxlan->gaddr; - } else - goto drop; - ttl = vxlan->ttl; if (!ttl && IN_MULTICAST(ntohl(dst))) ttl = 1; @@ -669,11 +713,15 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (tos == 1) tos = vxlan_get_dsfield(old_iph, skb); - hash = skb_get_rxhash(skb); + src_port = vxlan_src_port(vxlan, skb); + + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_oif = vxlan->link; + fl4.flowi4_tos = RT_TOS(tos); + fl4.daddr = dst; + fl4.saddr = vxlan->saddr; - rt = ip_route_output_gre(dev_net(dev), &fl4, dst, - vxlan->saddr, vxlan->vni, - RT_TOS(tos), vxlan->link); + rt = ip_route_output_key(dev_net(dev), &fl4); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to %pI4\n", &dst); dev->stats.tx_carrier_errors++; @@ -702,7 +750,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) uh = udp_hdr(skb); uh->dest = htons(vxlan_port); - uh->source = hash ? :random32(); + uh->source = htons(src_port); uh->len = htons(skb->len); uh->check = 0; @@ -715,10 +763,12 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) iph->frag_off = df; iph->protocol = IPPROTO_UDP; iph->tos = vxlan_ecn_encap(tos, old_iph, skb); - iph->daddr = fl4.daddr; + iph->daddr = dst; iph->saddr = fl4.saddr; iph->ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + vxlan_set_owner(dev, skb); + /* See __IPTUNNEL_XMIT */ skb->ip_summed = CHECKSUM_NONE; ip_select_ident(iph, &rt->dst, NULL); @@ -928,9 +978,11 @@ static void vxlan_setup(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); unsigned h; + int low, high; eth_hw_addr_random(dev); ether_setup(dev); + dev->hard_header_len = ETH_HLEN + VXLAN_HEADROOM; dev->netdev_ops = &vxlan_netdev_ops; dev->destructor = vxlan_free; @@ -947,6 +999,10 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.function = vxlan_cleanup; vxlan->age_timer.data = (unsigned long) vxlan; + inet_get_local_port_range(&low, &high); + vxlan->port_min = low; + vxlan->port_max = high; + vxlan->dev = dev; for (h = 0; h < FDB_HASH_SIZE; ++h) @@ -963,6 +1019,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 }, [IFLA_VXLAN_AGEING] = { .type = NLA_U32 }, [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 }, + [IFLA_VXLAN_PORT_RANGE] = { .len = sizeof(struct ifla_vxlan_port_range) }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -995,6 +1052,18 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) return -EADDRNOTAVAIL; } } + + if (data[IFLA_VXLAN_PORT_RANGE]) { + const struct ifla_vxlan_port_range *p + = nla_data(data[IFLA_VXLAN_PORT_RANGE]); + + if (ntohs(p->high) < ntohs(p->low)) { + pr_debug("port range %u .. %u not valid\n", + ntohs(p->low), ntohs(p->high)); + return -EINVAL; + } + } + return 0; } @@ -1021,14 +1090,18 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (data[IFLA_VXLAN_LOCAL]) vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]); - if (data[IFLA_VXLAN_LINK]) { - vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]); + if (data[IFLA_VXLAN_LINK] && + (vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]))) { + struct net_device *lowerdev + = __dev_get_by_index(net, vxlan->link); - if (!tb[IFLA_MTU]) { - struct net_device *lowerdev; - lowerdev = __dev_get_by_index(net, vxlan->link); - dev->mtu = lowerdev->mtu - VXLAN_HEADROOM; + if (!lowerdev) { + pr_info("ifindex %d does not exist\n", vxlan->link); + return -ENODEV; } + + if (!tb[IFLA_MTU]) + dev->mtu = lowerdev->mtu - VXLAN_HEADROOM; } if (data[IFLA_VXLAN_TOS]) @@ -1045,6 +1118,13 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (data[IFLA_VXLAN_LIMIT]) vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); + if (data[IFLA_VXLAN_PORT_RANGE]) { + const struct ifla_vxlan_port_range *p + = nla_data(data[IFLA_VXLAN_PORT_RANGE]); + vxlan->port_min = ntohs(p->low); + vxlan->port_max = ntohs(p->high); + } + err = register_netdevice(dev); if (!err) hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni)); @@ -1073,12 +1153,17 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */ + nla_total_size(sizeof(struct ifla_vxlan_port_range)) + 0; } static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) { const struct vxlan_dev *vxlan = netdev_priv(dev); + struct ifla_vxlan_port_range ports = { + .low = htons(vxlan->port_min), + .high = htons(vxlan->port_max), + }; if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni)) goto nla_put_failure; @@ -1099,6 +1184,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax)) goto nla_put_failure; + if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9fd6d9a9942e..9f31cfa56cc0 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1804,7 +1804,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int ret; struct ath5k_hw *ah = hw->priv; - struct ath5k_vif *avf = (void *)vif->drv_priv; + struct ath5k_vif *avf; struct sk_buff *skb; if (WARN_ON(!vif)) { @@ -1819,6 +1819,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } + avf = (void *)vif->drv_priv; ath5k_txbuf_free_skb(ah, avf->bbuf); avf->bbuf->skb = skb; ret = ath5k_beacon_setup(ah, avf->bbuf); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 76f07d8c272d..1b48414dca95 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -120,7 +120,7 @@ static void ath9k_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) if (ath_tx_start(hw, skb, &txctl) != 0) { ath_dbg(common, XMIT, "CABQ TX failed\n"); - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f9a6ec5cf470..8e1559aba495 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1450,9 +1450,14 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + if (!ah->reset_power_on) + type = ATH9K_RESET_POWER_ON; + switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); + if (!ret) + ah->reset_power_on = true; break; case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 566a4ce4f156..dbc1b7a4cbfd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -741,6 +741,7 @@ struct ath_hw { u32 rfkill_polarity; u32 ah_flags; + bool reset_power_on; bool htc_reset_init; enum nl80211_iftype opmode; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 31ab82e3ba85..dd45edfa6bae 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -639,8 +639,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_err(common, "Unable to reset hardware; reset status %d (freq %u MHz)\n", r, curchan->center_freq); - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; + ah->reset_power_on = false; } /* Setup our intr mask. */ @@ -665,11 +664,8 @@ static int ath9k_start(struct ieee80211_hw *hw) clear_bit(SC_OP_INVALID, &sc->sc_flags); sc->sc_ah->is_monitoring = false; - if (!ath_complete_reset(sc, false)) { - r = -EIO; - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; - } + if (!ath_complete_reset(sc, false)) + ah->reset_power_on = false; if (ah->led_pin >= 0) { ath9k_hw_cfg_output(ah, ah->led_pin, @@ -688,12 +684,11 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) common->bus_ops->extn_synch_en(common); -mutex_unlock: mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); - return r; + return 0; } static void ath9k_tx(struct ieee80211_hw *hw, @@ -770,7 +765,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, return; exit: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void ath9k_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 0e630a99b68b..f088f4bf9a26 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -324,6 +324,10 @@ static int ath_pci_suspend(struct device *device) static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u32 val; /* @@ -335,6 +339,9 @@ static int ath_pci_resume(struct device *device) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + ath_pci_aspm_init(common); + ah->reset_power_on = false; + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 36618e3a5e60..378bd70256b2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -66,8 +66,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, @@ -176,7 +175,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) fi = get_frame_info(skb); bf = fi->bf; - if (bf && fi->retries) { + if (!bf) { + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + if (!bf) { + ieee80211_free_txskb(sc->hw, skb); + continue; + } + } + + if (fi->retries) { list_add_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); @@ -785,10 +792,13 @@ 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) + if (!bf) { + __skb_unlink(skb, &tid->buf_q); + ieee80211_free_txskb(sc->hw, skb); continue; + } bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; @@ -1731,9 +1741,11 @@ 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); - if (!bf) + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + ieee80211_free_txskb(sc->hw, skb); return; + } bf->bf_state.bf_type = BUF_AMPDU; INIT_LIST_HEAD(&bf_head); @@ -1757,11 +1769,6 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; bf = fi->bf; - if (!bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, false); - - if (!bf) - return; INIT_LIST_HEAD(&bf_head); list_add_tail(&bf->list, &bf_head); @@ -1839,8 +1846,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); @@ -1852,7 +1858,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, bf = ath_tx_get_buffer(sc); if (!bf) { ath_dbg(common, XMIT, "TX buffers are full\n"); - goto error; + return NULL; } ATH_TXBUF_RESET(bf); @@ -1881,18 +1887,12 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, ath_err(ath9k_hw_common(sc->sc_ah), "dma_mapping_error() on TX\n"); ath_tx_return_buffer(sc, bf); - goto error; + return NULL; } fi->bf = bf; return bf; - -error: - if (dequeue) - __skb_unlink(skb, &tid->buf_q); - dev_kfree_skb_any(skb); - return NULL; } /* FIXME: tx power */ @@ -1921,9 +1921,14 @@ 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); - if (!bf) + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + if (txctl->paprd) + dev_kfree_skb_any(skb); + else + ieee80211_free_txskb(sc->hw, skb); return; + } bf->bf_state.bfs_paprd = txctl->paprd; diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 2aa4a59c72c8..2df17f1e49ef 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -303,6 +303,7 @@ struct ar9170 { unsigned long queue_stop_timeout[__AR9170_NUM_TXQ]; unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ]; bool needs_full_reset; + bool force_usb_reset; atomic_t pending_restarts; /* interface mode settings */ diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 67997b39aba7..25a1e2f4f738 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -465,27 +465,26 @@ static void carl9170_restart_work(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, restart_work); - int err; + int err = -EIO; ar->usedkeys = 0; ar->filter_state = 0; carl9170_cancel_worker(ar); mutex_lock(&ar->mutex); - err = carl9170_usb_restart(ar); - if (net_ratelimit()) { - if (err) { - dev_err(&ar->udev->dev, "Failed to restart device " - " (%d).\n", err); - } else { - dev_info(&ar->udev->dev, "device restarted " - "successfully.\n"); + if (!ar->force_usb_reset) { + err = carl9170_usb_restart(ar); + if (net_ratelimit()) { + if (err) + dev_err(&ar->udev->dev, "Failed to restart device (%d).\n", err); + else + dev_info(&ar->udev->dev, "device restarted successfully.\n"); } } - carl9170_zap_queues(ar); mutex_unlock(&ar->mutex); - if (!err) { + + if (!err && !ar->force_usb_reset) { ar->restart_counter++; atomic_set(&ar->pending_restarts, 0); @@ -526,10 +525,10 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r) if (!ar->registered) return; - if (IS_ACCEPTING_CMD(ar) && !ar->needs_full_reset) - ieee80211_queue_work(ar->hw, &ar->restart_work); - else - carl9170_usb_reset(ar); + if (!IS_ACCEPTING_CMD(ar) || ar->needs_full_reset) + ar->force_usb_reset = true; + + ieee80211_queue_work(ar->hw, &ar->restart_work); /* * At this point, the device instance might have vanished/disabled. diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 2691620393ea..0679458a1bac 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1596,8 +1596,9 @@ done: } } - if (mwifiex_bss_start(priv, bss, &req_ssid)) - return -EFAULT; + ret = mwifiex_bss_start(priv, bss, &req_ssid); + if (ret) + return ret; if (mode == NL80211_IFTYPE_ADHOC) { /* Inform the BSS information to kernel, otherwise @@ -1652,9 +1653,19 @@ done: "info: association to bssid %pM failed\n", priv->cfg_bssid); memset(priv->cfg_bssid, 0, ETH_ALEN); + + if (ret > 0) + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, + NULL, 0, NULL, 0, ret, + GFP_KERNEL); + else + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); } - return ret; + return 0; } /* @@ -1802,7 +1813,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, { struct net_device *dev = request->wdev->netdev; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - int i, offset; + int i, offset, ret; struct ieee80211_channel *chan; struct ieee_types_header *ie; @@ -1855,8 +1866,12 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, priv->user_scan_cfg->chan_list[i].scan_time = 0; } - if (mwifiex_scan_networks(priv, priv->user_scan_cfg)) - return -EFAULT; + + ret = mwifiex_scan_networks(priv, priv->user_scan_cfg); + if (ret) { + dev_err(priv->adapter->dev, "scan failed: %d\n", ret); + return ret; + } if (request->ie && request->ie_len) { for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 82e63cee1e97..7b0858af8f5d 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1180,16 +1180,18 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; struct mwifiex_bssdescriptor *bss_desc; + u16 reason_code; adhoc_result = &resp->params.adhoc_result; bss_desc = priv->attempted_bss_desc; /* Join result code 0 --> SUCCESS */ - if (le16_to_cpu(resp->result)) { + reason_code = le16_to_cpu(resp->result); + if (reason_code) { dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); if (priv->media_connected) - mwifiex_reset_connect_state(priv); + mwifiex_reset_connect_state(priv, reason_code); memset(&priv->curr_bss_params.bss_descriptor, 0x00, sizeof(struct mwifiex_bssdescriptor)); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index bfb3fa69805c..c2d0ab146af5 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -847,7 +847,7 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -void mwifiex_reset_connect_state(struct mwifiex_private *priv); +void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason); u8 mwifiex_band_to_radio_type(u8 band); int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); int mwifiex_adhoc_start(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index e36a75988f87..00b658d3b6ec 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1296,7 +1296,7 @@ mwifiex_radio_type_to_band(u8 radio_type) int mwifiex_scan_networks(struct mwifiex_private *priv, const struct mwifiex_user_scan_cfg *user_scan_in) { - int ret = 0; + int ret; struct mwifiex_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmd_node; union mwifiex_scan_cmd_config_tlv *scan_cfg_out; @@ -1309,25 +1309,26 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, unsigned long flags; if (adapter->scan_processing) { - dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); - return ret; + dev_err(adapter->dev, "cmd: Scan already in process...\n"); + return -EBUSY; } - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = true; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - if (priv->scan_block) { - dev_dbg(adapter->dev, + dev_err(adapter->dev, "cmd: Scan is blocked during association...\n"); - return ret; + return -EBUSY; } + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), GFP_KERNEL); if (!scan_cfg_out) { dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); - return -ENOMEM; + ret = -ENOMEM; + goto done; } buf_size = sizeof(struct mwifiex_chan_scan_param_set) * @@ -1336,7 +1337,8 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, if (!scan_chan_list) { dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); kfree(scan_cfg_out); - return -ENOMEM; + ret = -ENOMEM; + goto done; } mwifiex_config_scan(priv, user_scan_in, &scan_cfg_out->config, @@ -1364,14 +1366,16 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); } - } else { - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = true; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); } kfree(scan_cfg_out); kfree(scan_chan_list); +done: + if (ret) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } return ret; } @@ -1430,8 +1434,8 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, ret = mwifiex_is_network_compatible(priv, bss_desc, priv->bss_mode); if (ret) - dev_err(priv->adapter->dev, "cannot find ssid " - "%s\n", bss_desc->ssid.ssid); + dev_err(priv->adapter->dev, + "Incompatible network settings\n"); break; default: ret = 0; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index e380171c4c5d..09e6a267f566 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -545,7 +545,7 @@ static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, if (!memcmp(resp->params.deauth.mac_addr, &priv->curr_bss_params.bss_descriptor.mac_address, sizeof(resp->params.deauth.mac_addr))) - mwifiex_reset_connect_state(priv); + mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING); return 0; } @@ -558,7 +558,7 @@ static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { - mwifiex_reset_connect_state(priv); + mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING); return 0; } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index aafde30e714a..8132119e1a21 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -41,7 +41,7 @@ * - Sends a disconnect event to upper layers/applications. */ void -mwifiex_reset_connect_state(struct mwifiex_private *priv) +mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) { struct mwifiex_adapter *adapter = priv->adapter; @@ -117,10 +117,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) priv->media_connected = false; dev_dbg(adapter->dev, "info: successfully disconnected from %pM: reason code %d\n", - priv->cfg_bssid, WLAN_REASON_DEAUTH_LEAVING); + priv->cfg_bssid, reason_code); if (priv->bss_mode == NL80211_IFTYPE_STATION) { - cfg80211_disconnected(priv->netdev, WLAN_REASON_DEAUTH_LEAVING, - NULL, 0, GFP_KERNEL); + cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, + GFP_KERNEL); } memset(priv->cfg_bssid, 0, ETH_ALEN); @@ -186,7 +186,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; u32 eventcause = adapter->event_cause; - u16 ctrl; + u16 ctrl, reason_code; switch (eventcause) { case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: @@ -204,22 +204,31 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_DEAUTHENTICATED: dev_dbg(adapter->dev, "event: Deauthenticated\n"); adapter->dbg.num_event_deauth++; - if (priv->media_connected) - mwifiex_reset_connect_state(priv); + if (priv->media_connected) { + reason_code = + le16_to_cpu(*(__le16 *)adapter->event_body); + mwifiex_reset_connect_state(priv, reason_code); + } break; case EVENT_DISASSOCIATED: dev_dbg(adapter->dev, "event: Disassociated\n"); adapter->dbg.num_event_disassoc++; - if (priv->media_connected) - mwifiex_reset_connect_state(priv); + if (priv->media_connected) { + reason_code = + le16_to_cpu(*(__le16 *)adapter->event_body); + mwifiex_reset_connect_state(priv, reason_code); + } break; case EVENT_LINK_LOST: dev_dbg(adapter->dev, "event: Link lost\n"); adapter->dbg.num_event_link_lost++; - if (priv->media_connected) - mwifiex_reset_connect_state(priv); + if (priv->media_connected) { + reason_code = + le16_to_cpu(*(__le16 *)adapter->event_body); + mwifiex_reset_connect_state(priv, reason_code); + } break; case EVENT_PS_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 540c94f8505a..01dc8891070c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2252,9 +2252,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, */ if (rt2x00_rt(rt2x00dev, RT3352)) { rt2800_bbp_write(rt2x00dev, 27, 0x0); - rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain); rt2800_bbp_write(rt2x00dev, 27, 0x20); - rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain); } else { rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 4ebfcf3d8a3b..f2d6b78d901d 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -335,21 +335,35 @@ unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + unsigned long offset = skb_shinfo(skb)->frags[i].page_offset; unsigned long bytes; + + offset &= ~PAGE_MASK; + while (size > 0) { + BUG_ON(offset >= PAGE_SIZE); BUG_ON(copy_off > MAX_BUFFER_OFFSET); - if (start_new_rx_buffer(copy_off, size, 0)) { + bytes = PAGE_SIZE - offset; + + if (bytes > size) + bytes = size; + + if (start_new_rx_buffer(copy_off, bytes, 0)) { count++; copy_off = 0; } - bytes = size; if (copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - copy_off; copy_off += bytes; + + offset += bytes; size -= bytes; + + if (offset == PAGE_SIZE) + offset = 0; } } return count; @@ -403,14 +417,24 @@ static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, unsigned long bytes; /* Data must not cross a page boundary. */ - BUG_ON(size + offset > PAGE_SIZE); + BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); meta = npo->meta + npo->meta_prod - 1; + /* Skip unused frames from start of page */ + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; + while (size > 0) { + BUG_ON(offset >= PAGE_SIZE); BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); - if (start_new_rx_buffer(npo->copy_off, size, *head)) { + bytes = PAGE_SIZE - offset; + + if (bytes > size) + bytes = size; + + if (start_new_rx_buffer(npo->copy_off, bytes, *head)) { /* * Netfront requires there to be some data in the head * buffer. @@ -420,7 +444,6 @@ static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, meta = get_next_rx_buffer(vif, npo); } - bytes = size; if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - npo->copy_off; @@ -453,6 +476,13 @@ static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, offset += bytes; size -= bytes; + /* Next frame */ + if (offset == PAGE_SIZE && size) { + BUG_ON(!PageCompound(page)); + page++; + offset = 0; + } + /* Leave a gap for the GSO descriptor. */ if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix) vif->rx.req_cons++; diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c index ec6209dd7c39..debaa75b0552 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -725,10 +725,10 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C), - /* Other alt C1 column, these are still configured as alt C */ - DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C), - DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C), - DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C), + /* Other alt C1 column */ + DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1), }; /* We use this macro to define the groups applicable to a function */ @@ -860,6 +860,284 @@ static const struct nmk_function nmk_db8500_functions[] = { FUNCTION(spi2), }; +static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = { + PRCM_GPIOCR_ALTCX(23, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_CLK_a */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_CLK_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(24, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE or U2_RXD ??? */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_VAL_a */ + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(25, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[0] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[0] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(26, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[1] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[1] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(27, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[2] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[2] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(28, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[3] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[3] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(29, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(30, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(31, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(32, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(68, true, PRCM_IDX_GPIOCR1, 18, /* REMAP_SELECT_ON */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(69, true, PRCM_IDX_GPIOCR1, 18, /* REMAP_SELECT_ON */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(70, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D23 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_CLK */ + ), + PRCM_GPIOCR_ALTCX(71, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D22 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D3 */ + ), + PRCM_GPIOCR_ALTCX(72, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D21 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D2 */ + ), + PRCM_GPIOCR_ALTCX(73, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D20 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D1 */ + ), + PRCM_GPIOCR_ALTCX(74, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D19 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D0 */ + ), + PRCM_GPIOCR_ALTCX(75, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D18 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 0, /* DBG_UARTMOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(76, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D17 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 0, /* DBG_UARTMOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(77, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D16 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_VAL */ + ), + PRCM_GPIOCR_ALTCX(86, true, PRCM_IDX_GPIOCR1, 12, /* KP_O3 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(87, true, PRCM_IDX_GPIOCR1, 12, /* KP_O2 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(88, true, PRCM_IDX_GPIOCR1, 12, /* KP_I3 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(89, true, PRCM_IDX_GPIOCR1, 12, /* KP_I2 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(90, true, PRCM_IDX_GPIOCR1, 12, /* KP_O1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(91, true, PRCM_IDX_GPIOCR1, 12, /* KP_O0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(92, true, PRCM_IDX_GPIOCR1, 12, /* KP_I1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(93, true, PRCM_IDX_GPIOCR1, 12, /* KP_I0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(96, true, PRCM_IDX_GPIOCR2, 3, /* RF_INT */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(97, true, PRCM_IDX_GPIOCR2, 1, /* RF_CTRL */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(151, false, 0, 0, + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_CTL */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS17 */ + ), + PRCM_GPIOCR_ALTCX(152, true, PRCM_IDX_GPIOCR1, 4, /* Hx_CLK */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_CLK */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS16 */ + ), + PRCM_GPIOCR_ALTCX(153, true, PRCM_IDX_GPIOCR1, 1, /* UARTMOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D15 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS15 */ + ), + PRCM_GPIOCR_ALTCX(154, true, PRCM_IDX_GPIOCR1, 1, /* UARTMOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D14 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS14 */ + ), + PRCM_GPIOCR_ALTCX(155, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D13 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS13 */ + ), + PRCM_GPIOCR_ALTCX(156, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D12 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS12 */ + ), + PRCM_GPIOCR_ALTCX(157, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D11 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS11 */ + ), + PRCM_GPIOCR_ALTCX(158, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D10 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS10 */ + ), + PRCM_GPIOCR_ALTCX(159, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D9 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS9 */ + ), + PRCM_GPIOCR_ALTCX(160, false, 0, 0, + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D8 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS8 */ + ), + PRCM_GPIOCR_ALTCX(161, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO7 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D7 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS7 */ + ), + PRCM_GPIOCR_ALTCX(162, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO6 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D6 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS6 */ + ), + PRCM_GPIOCR_ALTCX(163, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO5 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D5 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS5 */ + ), + PRCM_GPIOCR_ALTCX(164, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO4 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D4 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS4 */ + ), + PRCM_GPIOCR_ALTCX(165, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO3 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D3 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS3 */ + ), + PRCM_GPIOCR_ALTCX(166, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO2 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D2 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS2 */ + ), + PRCM_GPIOCR_ALTCX(167, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO1 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D1 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS1 */ + ), + PRCM_GPIOCR_ALTCX(168, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO0 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D0 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS0 */ + ), + PRCM_GPIOCR_ALTCX(170, true, PRCM_IDX_GPIOCR2, 2, /* RF_INT */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(171, true, PRCM_IDX_GPIOCR2, 0, /* RF_CTRL */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(215, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_TXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(216, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_FRM */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(217, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_CLK */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(218, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_RXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), +}; + +static const u16 db8500_prcm_gpiocr_regs[] = { + [PRCM_IDX_GPIOCR1] = 0x138, + [PRCM_IDX_GPIOCR2] = 0x574, +}; + static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { .gpio_ranges = nmk_db8500_ranges, .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges), @@ -869,6 +1147,9 @@ static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { .nfunctions = ARRAY_SIZE(nmk_db8500_functions), .groups = nmk_db8500_groups, .ngroups = ARRAY_SIZE(nmk_db8500_groups), + .altcx_pins = db8500_altcx_pins, + .npins_altcx = ARRAY_SIZE(db8500_altcx_pins), + .prcm_gpiocr_registers = db8500_prcm_gpiocr_regs, }; void __devinit diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c index 3daf665c84c3..52fc30181f7e 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8540.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8540.c @@ -778,50 +778,50 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { DB8540_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), DB8540_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C), - /* Other alt C1 column, these are still configured as alt C */ - DB8540_PIN_GROUP(spi3_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsrefclk_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobspwrctrl_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsclkout_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart1_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modprcmudbg_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsresout_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccgpo_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modxmip_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(i2c6_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2txrx_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2ctsrts_oc1_1, NMK_GPIO_ALT_C), + /* Other alt C1 column */ + DB8540_PIN_GROUP(spi3_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(u2_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobsrefclk_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobspwrctrl_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobsclkout_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(moduart1_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modprcmudbg_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobsresout_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modaccgpo_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modxmip_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(i2c6_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(u2txrx_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(u2ctsrts_oc1_1, NMK_GPIO_ALT_C1), - /* Other alt C2 column, these are still configured as alt C */ - DB8540_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(hxclk_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccuart_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmmod_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduartstmmux_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(hxgpio_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(sbag_oc2_2, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsservice_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart0_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmape_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modxmip_oc2_1, NMK_GPIO_ALT_C), + /* Other alt C2 column */ + DB8540_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(hxclk_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(modaccuart_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(stmmod_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(moduartstmmux_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(hxgpio_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(sbag_oc2_2, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(modobsservice_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(moduart0_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(stmape_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(u2_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(modxmip_oc2_1, NMK_GPIO_ALT_C2), - /* Other alt C3 column, these are still configured as alt C */ - DB8540_PIN_GROUP(modaccgpo_oc3_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(tpui_oc3_1, NMK_GPIO_ALT_C), + /* Other alt C3 column */ + DB8540_PIN_GROUP(modaccgpo_oc3_1, NMK_GPIO_ALT_C3), + DB8540_PIN_GROUP(tpui_oc3_1, NMK_GPIO_ALT_C3), - /* Other alt C4 column, these are still configured as alt C */ - DB8540_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart1txrx_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart1rtscts_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C), + /* Other alt C4 column */ + DB8540_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(moduart1txrx_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(moduart1rtscts_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C4), }; @@ -981,6 +981,265 @@ static const struct nmk_function nmk_db8540_functions[] = { FUNCTION(usb) }; +static const struct prcm_gpiocr_altcx_pin_desc db8540_altcx_pins[] = { + PRCM_GPIOCR_ALTCX(8, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_CLK */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(9, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_RXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(10, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_FRM */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(11, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_TXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(23, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_CLK_a */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_CLK_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(24, true, PRCM_IDX_GPIOCR3, 30, /* U2_RXD_g */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_VAL_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(25, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[0] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[0] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(26, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[1] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[1] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(27, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[2] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[2] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(28, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[3] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[3] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(64, true, PRCM_IDX_GPIOCR1, 15, /* MODOBS_REFCLK_REQ */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_CTL */ + true, PRCM_IDX_GPIOCR2, 23 /* HW_OBS_APE_PRCMU[17] */ + ), + PRCM_GPIOCR_ALTCX(65, true, PRCM_IDX_GPIOCR1, 19, /* MODOBS_PWRCTRL0 */ + true, PRCM_IDX_GPIOCR1, 24, /* Hx_CLK */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_CLK */ + true, PRCM_IDX_GPIOCR2, 24 /* HW_OBS_APE_PRCMU[16] */ + ), + PRCM_GPIOCR_ALTCX(66, true, PRCM_IDX_GPIOCR1, 15, /* MODOBS_CLKOUT1 */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[15] */ + true, PRCM_IDX_GPIOCR2, 25 /* HW_OBS_APE_PRCMU[15] */ + ), + PRCM_GPIOCR_ALTCX(67, true, PRCM_IDX_GPIOCR1, 1, /* MODUART1_TXD_a */ + true, PRCM_IDX_GPIOCR1, 6, /* MODACCUART_TXD_a */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[14] */ + true, PRCM_IDX_GPIOCR2, 26 /* HW_OBS_APE_PRCMU[14] */ + ), + PRCM_GPIOCR_ALTCX(70, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[17] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_CLK_b */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[13] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[13] */ + ), + PRCM_GPIOCR_ALTCX(71, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[16] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[3] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[12] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[12] */ + ), + PRCM_GPIOCR_ALTCX(72, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[15] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[2] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[11] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[11] */ + ), + PRCM_GPIOCR_ALTCX(73, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[14] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[1] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[10] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[10] */ + ), + PRCM_GPIOCR_ALTCX(74, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[13] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[0] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[9] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[9] */ + ), + PRCM_GPIOCR_ALTCX(75, true, PRCM_IDX_GPIOCR1, 12, /* MODOBS_RESOUT0_N */ + true, PRCM_IDX_GPIOCR2, 1, /* MODUART_STMMUX_RXD_b */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[8] */ + true, PRCM_IDX_GPIOCR2, 28 /* HW_OBS_APE_PRCMU[8] */ + ), + PRCM_GPIOCR_ALTCX(76, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[12] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[7] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[7] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[7] */ + ), + PRCM_GPIOCR_ALTCX(77, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[11] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[6] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[6] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[6] */ + ), + PRCM_GPIOCR_ALTCX(78, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[10] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[5] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[5] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[5] */ + ), + PRCM_GPIOCR_ALTCX(79, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[9] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[4] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[4] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[4] */ + ), + PRCM_GPIOCR_ALTCX(80, true, PRCM_IDX_GPIOCR1, 26, /* MODACC_GPO[0] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[3] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[3] */ + true, PRCM_IDX_GPIOCR2, 30 /* HW_OBS_APE_PRCMU[3] */ + ), + PRCM_GPIOCR_ALTCX(81, true, PRCM_IDX_GPIOCR2, 17, /* MODACC_GPO[1] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[2] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[2] */ + true, PRCM_IDX_GPIOCR2, 30 /* HW_OBS_APE_PRCMU[2] */ + ), + PRCM_GPIOCR_ALTCX(82, true, PRCM_IDX_GPIOCR3, 8, /* MOD_PRCMU_DEBUG[8] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[1] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[1] */ + true, PRCM_IDX_GPIOCR2, 31 /* HW_OBS_APE_PRCMU[1] */ + ), + PRCM_GPIOCR_ALTCX(83, true, PRCM_IDX_GPIOCR3, 8, /* MOD_PRCMU_DEBUG[7] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[0] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[0] */ + true, PRCM_IDX_GPIOCR2, 31 /* HW_OBS_APE_PRCMU[0] */ + ), + PRCM_GPIOCR_ALTCX(84, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[6] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_CLK_b */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[23] */ + true, PRCM_IDX_GPIOCR1, 16 /* MODUART1_RXD_b */ + ), + PRCM_GPIOCR_ALTCX(85, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[5] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[3] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[22] */ + true, PRCM_IDX_GPIOCR1, 16 /* MODUART1_TXD_b */ + ), + PRCM_GPIOCR_ALTCX(86, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[0] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[0] */ + true, PRCM_IDX_GPIOCR1, 14, /* TPIU_D[25] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[0] */ + ), + PRCM_GPIOCR_ALTCX(87, true, PRCM_IDX_GPIOCR3, 0, /* MODACC_GPO_a[5] */ + true, PRCM_IDX_GPIOCR2, 3, /* U2_RXD_c */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[24] */ + true, PRCM_IDX_GPIOCR1, 21 /* MODUART_STMMUX_RXD_c */ + ), + PRCM_GPIOCR_ALTCX(151, true, PRCM_IDX_GPIOCR1, 18, /* REMAP0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(152, true, PRCM_IDX_GPIOCR1, 18, /* REMAP1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(153, true, PRCM_IDX_GPIOCR3, 2, /* KP_O_b[6] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[2] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[21] */ + true, PRCM_IDX_GPIOCR1, 0 /* MODUART1_RTS */ + ), + PRCM_GPIOCR_ALTCX(154, true, PRCM_IDX_GPIOCR3, 2, /* KP_I_b[6] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[1] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[20] */ + true, PRCM_IDX_GPIOCR1, 0 /* MODUART1_CTS */ + ), + PRCM_GPIOCR_ALTCX(155, true, PRCM_IDX_GPIOCR3, 3, /* KP_O_b[5] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[0] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[19] */ + true, PRCM_IDX_GPIOCR1, 5 /* MODACCUART_RXD_c */ + ), + PRCM_GPIOCR_ALTCX(156, true, PRCM_IDX_GPIOCR3, 3, /* KP_O_b[4] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_VAL_b */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[18] */ + true, PRCM_IDX_GPIOCR1, 5 /* MODACCUART_TXD_b */ + ), + PRCM_GPIOCR_ALTCX(157, true, PRCM_IDX_GPIOCR3, 4, /* KP_I_b[5] */ + true, PRCM_IDX_GPIOCR1, 23, /* MODOBS_SERVICE_N */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[17] */ + true, PRCM_IDX_GPIOCR1, 14 /* MODACCUART_RTS */ + ), + PRCM_GPIOCR_ALTCX(158, true, PRCM_IDX_GPIOCR3, 4, /* KP_I_b[4] */ + true, PRCM_IDX_GPIOCR2, 0, /* U2_TXD_c */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[16] */ + true, PRCM_IDX_GPIOCR1, 14 /* MODACCUART_CTS */ + ), + PRCM_GPIOCR_ALTCX(159, true, PRCM_IDX_GPIOCR3, 5, /* KP_O_b[3] */ + true, PRCM_IDX_GPIOCR3, 10, /* MODUART0_RXD */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[31] */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(160, true, PRCM_IDX_GPIOCR3, 5, /* KP_I_b[3] */ + true, PRCM_IDX_GPIOCR3, 10, /* MODUART0_TXD */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[30] */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(161, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[4] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_CLK_b */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[29] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_CLK_c */ + ), + PRCM_GPIOCR_ALTCX(162, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[3] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[3] */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[28] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[3] */ + ), + PRCM_GPIOCR_ALTCX(163, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[2] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[2] */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[27] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[2] */ + ), + PRCM_GPIOCR_ALTCX(164, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[1] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[1] */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[26] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[1] */ + ), + PRCM_GPIOCR_ALTCX(204, true, PRCM_IDX_GPIOCR2, 2, /* U2_RXD_f */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(205, true, PRCM_IDX_GPIOCR2, 2, /* U2_TXD_f */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(206, true, PRCM_IDX_GPIOCR2, 2, /* U2_CTSn_b */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(207, true, PRCM_IDX_GPIOCR2, 2, /* U2_RTSn_b */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), +}; + +static const u16 db8540_prcm_gpiocr_regs[] = { + [PRCM_IDX_GPIOCR1] = 0x138, + [PRCM_IDX_GPIOCR2] = 0x574, + [PRCM_IDX_GPIOCR3] = 0x2bc, +}; + static const struct nmk_pinctrl_soc_data nmk_db8540_soc = { .gpio_ranges = nmk_db8540_ranges, .gpio_num_ranges = ARRAY_SIZE(nmk_db8540_ranges), @@ -990,6 +1249,9 @@ static const struct nmk_pinctrl_soc_data nmk_db8540_soc = { .nfunctions = ARRAY_SIZE(nmk_db8540_functions), .groups = nmk_db8540_groups, .ngroups = ARRAY_SIZE(nmk_db8540_groups), + .altcx_pins = db8540_altcx_pins, + .npins_altcx = ARRAY_SIZE(db8540_altcx_pins), + .prcm_gpiocr_registers = db8540_prcm_gpiocr_regs, }; void __devinit diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 6030a513f3c4..fec9c30133d4 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -30,6 +30,7 @@ #include <linux/pinctrl/pinconf.h> /* Since we request GPIOs from ourself */ #include <linux/pinctrl/consumer.h> +#include <linux/mfd/dbx500-prcmu.h> #include <asm/mach/irq.h> @@ -237,6 +238,89 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); } +static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, + unsigned offset, unsigned alt_num) +{ + int i; + u16 reg; + u8 bit; + u8 alt_index; + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { + dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", + alt_num); + return; + } + + for (i = 0 ; i < npct->soc->npins_altcx ; i++) { + if (npct->soc->altcx_pins[i].pin == offset) + break; + } + if (i == npct->soc->npins_altcx) { + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", + offset); + return; + } + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + + /* + * If alt_num is NULL, just clear current ALTCx selection + * to make sure we come back to a pure ALTC selection + */ + if (!alt_num) { + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (prcmu_read(reg) & BIT(bit)) { + prcmu_write_masked(reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + return; + } + + alt_index = alt_num - 1; + if (pin_desc->altcx[alt_index].used == false) { + dev_warn(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", + offset, alt_num); + return; + } + + /* + * Check if any other ALTCx functions are activated on this pin + * and disable it first. + */ + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (i == alt_index) + continue; + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (prcmu_read(reg) & BIT(bit)) { + prcmu_write_masked(reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + + reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; + bit = pin_desc->altcx[alt_index].control_bit; + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", + offset, alt_index+1); + prcmu_write_masked(reg, BIT(bit), BIT(bit)); +} + static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) { @@ -1287,9 +1371,19 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) platform_set_drvdata(dev, nmk_chip); - nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP, - NOMADIK_GPIO_TO_IRQ(pdata->first_gpio), - 0, &nmk_gpio_irq_simple_ops, nmk_chip); + if (np) { + /* The DT case will just grab a set of IRQ numbers */ + nmk_chip->domain = irq_domain_add_linear(np, NMK_GPIO_PER_CHIP, + &nmk_gpio_irq_simple_ops, nmk_chip); + } else { + /* Non-DT legacy mode, use hardwired IRQ numbers */ + int irq_start; + + irq_start = NOMADIK_GPIO_TO_IRQ(pdata->first_gpio); + nmk_chip->domain = irq_domain_add_simple(NULL, + NMK_GPIO_PER_CHIP, irq_start, + &nmk_gpio_irq_simple_ops, nmk_chip); + } if (!nmk_chip->domain) { dev_err(&dev->dev, "failed to create irqdomain\n"); ret = -ENOSYS; @@ -1441,7 +1535,7 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, * IOFORCE will switch *all* ports to their sleepmode setting to as * to avoid glitches. (Not just one port!) */ - glitch = (g->altsetting == NMK_GPIO_ALT_C); + glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); if (glitch) { spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); @@ -1491,8 +1585,21 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, */ nmk_gpio_disable_lazy_irq(nmk_chip, bit); - __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch); + __nmk_gpio_set_mode_safe(nmk_chip, bit, + (g->altsetting & NMK_GPIO_ALT_C), glitch); clk_disable(nmk_chip->clk); + + /* + * Call PRCM GPIOCR config function in case ALTC + * has been selected: + * - If selection is a ALTCx, some bits in PRCM GPIOCR registers + * must be set. + * - If selection is pure ALTC and previous selection was ALTCx, + * then some bits in PRCM GPIOCR registers must be cleared. + */ + if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) + nmk_prcm_altcx_set_mode(npct, g->pins[i], + g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); } /* When all pins are successfully reconfigured we get here */ diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h index 5c99f1c62dfd..eef316e979a0 100644 --- a/drivers/pinctrl/pinctrl-nomadik.h +++ b/drivers/pinctrl/pinctrl-nomadik.h @@ -8,6 +8,78 @@ #define PINCTRL_NMK_DB8500 1 #define PINCTRL_NMK_DB8540 2 +#define PRCM_GPIOCR_ALTCX(pin_num,\ + altc1_used, altc1_ri, altc1_cb,\ + altc2_used, altc2_ri, altc2_cb,\ + altc3_used, altc3_ri, altc3_cb,\ + altc4_used, altc4_ri, altc4_cb)\ +{\ + .pin = pin_num,\ + .altcx[PRCM_IDX_GPIOCR_ALTC1] = {\ + .used = altc1_used,\ + .reg_index = altc1_ri,\ + .control_bit = altc1_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC2] = {\ + .used = altc2_used,\ + .reg_index = altc2_ri,\ + .control_bit = altc2_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC3] = {\ + .used = altc3_used,\ + .reg_index = altc3_ri,\ + .control_bit = altc3_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC4] = {\ + .used = altc4_used,\ + .reg_index = altc4_ri,\ + .control_bit = altc4_cb\ + },\ +} + +/** + * enum prcm_gpiocr_reg_index + * Used to reference an PRCM GPIOCR register address. + */ +enum prcm_gpiocr_reg_index { + PRCM_IDX_GPIOCR1, + PRCM_IDX_GPIOCR2, + PRCM_IDX_GPIOCR3 +}; +/** + * enum prcm_gpiocr_altcx_index + * Used to reference an Other alternate-C function. + */ +enum prcm_gpiocr_altcx_index { + PRCM_IDX_GPIOCR_ALTC1, + PRCM_IDX_GPIOCR_ALTC2, + PRCM_IDX_GPIOCR_ALTC3, + PRCM_IDX_GPIOCR_ALTC4, + PRCM_IDX_GPIOCR_ALTC_MAX, +}; + +/** + * struct prcm_gpio_altcx - Other alternate-C function + * @used: other alternate-C function availability + * @reg_index: PRCM GPIOCR register index used to control the function + * @control_bit: PRCM GPIOCR bit used to control the function + */ +struct prcm_gpiocr_altcx { + bool used:1; + u8 reg_index:2; + u8 control_bit:5; +} __packed; + +/** + * struct prcm_gpio_altcx_pin_desc - Other alternate-C pin + * @pin: The pin number + * @altcx: array of other alternate-C[1-4] functions + */ +struct prcm_gpiocr_altcx_pin_desc { + unsigned short pin; + struct prcm_gpiocr_altcx altcx[PRCM_IDX_GPIOCR_ALTC_MAX]; +}; + /** * struct nmk_function - Nomadik pinctrl mux function * @name: The name of the function, exported to pinctrl core. @@ -50,6 +122,9 @@ struct nmk_pingroup { * @nfunction: The number of entries in @functions. * @groups: An array describing all pin groups the pin SoC supports. * @ngroups: The number of entries in @groups. + * @altcx_pins: The pins that support Other alternate-C function on this SoC + * @npins_altcx: The number of Other alternate-C pins + * @prcm_gpiocr_registers: The array of PRCM GPIOCR registers on this SoC */ struct nmk_pinctrl_soc_data { struct pinctrl_gpio_range *gpio_ranges; @@ -60,6 +135,9 @@ struct nmk_pinctrl_soc_data { unsigned nfunctions; const struct nmk_pingroup *groups; unsigned ngroups; + const struct prcm_gpiocr_altcx_pin_desc *altcx_pins; + unsigned npins_altcx; + const u16 *prcm_gpiocr_registers; }; #ifdef CONFIG_PINCTRL_STN8815 diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c index d4957b4edb62..24768a27e1d8 100644 --- a/drivers/power/avs/smartreflex.c +++ b/drivers/power/avs/smartreflex.c @@ -930,7 +930,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) if (!sr_info->base) { dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); ret = -ENOMEM; - goto err_release_region; + goto err_free_name; } if (irq) @@ -969,7 +969,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", __func__); ret = PTR_ERR(sr_info->dbg_dir); - goto err_free_name; + goto err_debugfs; } (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, @@ -1013,11 +1013,11 @@ static int __init omap_sr_probe(struct platform_device *pdev) err_debugfs: debugfs_remove_recursive(sr_info->dbg_dir); -err_free_name: - kfree(sr_info->name); err_iounmap: list_del(&sr_info->node); iounmap(sr_info->base); +err_free_name: + kfree(sr_info->name); err_release_region: release_mem_region(mem->start, resource_size(mem)); err_free_devinfo: diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 48e9041dd1e2..07da58bb495c 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -55,9 +55,9 @@ static int rio_mport_phys_table[] = { }; -/* +/** * rio_destid_alloc - Allocate next available destID for given network - * net: RIO network + * @net: RIO network * * Returns next available device destination ID for the specified RIO network. * Marks allocated ID as one in use. @@ -69,14 +69,9 @@ static u16 rio_destid_alloc(struct rio_net *net) struct rio_id_table *idtab = &net->destid_table; spin_lock(&idtab->lock); - destid = find_next_zero_bit(idtab->table, idtab->max, idtab->next); - if (destid >= idtab->max) - destid = find_first_zero_bit(idtab->table, idtab->max); + destid = find_first_zero_bit(idtab->table, idtab->max); if (destid < idtab->max) { - idtab->next = destid + 1; - if (idtab->next >= idtab->max) - idtab->next = 0; set_bit(destid, idtab->table); destid += idtab->start; } else @@ -86,10 +81,10 @@ static u16 rio_destid_alloc(struct rio_net *net) return (u16)destid; } -/* +/** * rio_destid_reserve - Reserve the specivied destID - * net: RIO network - * destid: destID to reserve + * @net: RIO network + * @destid: destID to reserve * * Tries to reserve the specified destID. * Returns 0 if successfull. @@ -106,10 +101,10 @@ static int rio_destid_reserve(struct rio_net *net, u16 destid) return oldbit; } -/* +/** * rio_destid_free - free a previously allocated destID - * net: RIO network - * destid: destID to free + * @net: RIO network + * @destid: destID to free * * Makes the specified destID available for use. */ @@ -123,9 +118,9 @@ static void rio_destid_free(struct rio_net *net, u16 destid) spin_unlock(&idtab->lock); } -/* +/** * rio_destid_first - return first destID in use - * net: RIO network + * @net: RIO network */ static u16 rio_destid_first(struct rio_net *net) { @@ -142,10 +137,10 @@ static u16 rio_destid_first(struct rio_net *net) return (u16)destid; } -/* +/** * rio_destid_next - return next destID in use - * net: RIO network - * from: destination ID from which search shall continue + * @net: RIO network + * @from: destination ID from which search shall continue */ static u16 rio_destid_next(struct rio_net *net, u16 from) { @@ -1163,8 +1158,8 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port, net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); if (net && do_enum) { - net->destid_table.table = kzalloc( - BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)) * + net->destid_table.table = kcalloc( + BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)), sizeof(long), GFP_KERNEL); @@ -1174,7 +1169,6 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port, net = NULL; } else { net->destid_table.start = start; - net->destid_table.next = 0; net->destid_table.max = RIO_MAX_ROUTE_ENTRIES(port->sys_size); spin_lock_init(&net->destid_table.lock); @@ -1391,7 +1385,7 @@ int __devinit rio_disc_mport(struct rio_mport *mport) while (time_before(jiffies, to_end)) { if (rio_enum_complete(mport)) goto enum_done; - schedule_timeout_uninterruptible(msecs_to_jiffies(10)); + msleep(10); } pr_debug("RIO: discovery timeout on mport %d %s\n", diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index d4bd69013c50..c17ae22567e0 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1275,49 +1275,68 @@ static void __devinit disc_work_handler(struct work_struct *_work) pr_debug("RIO: discovery work for mport %d %s\n", work->mport->id, work->mport->name); rio_disc_mport(work->mport); - - kfree(work); } int __devinit rio_init_mports(void) { struct rio_mport *port; struct rio_disc_work *work; - int no_disc = 0; + int n = 0; + + if (!next_portid) + return -ENODEV; + /* + * First, run enumerations and check if we need to perform discovery + * on any of the registered mports. + */ list_for_each_entry(port, &rio_mports, node) { if (port->host_deviceid >= 0) rio_enum_mport(port); - else if (!no_disc) { - if (!rio_wq) { - rio_wq = alloc_workqueue("riodisc", 0, 0); - if (!rio_wq) { - pr_err("RIO: unable allocate rio_wq\n"); - no_disc = 1; - continue; - } - } - - work = kzalloc(sizeof *work, GFP_KERNEL); - if (!work) { - pr_err("RIO: no memory for work struct\n"); - no_disc = 1; - continue; - } - - work->mport = port; - INIT_WORK(&work->work, disc_work_handler); - queue_work(rio_wq, &work->work); - } + else + n++; + } + + if (!n) + goto no_disc; + + /* + * If we have mports that require discovery schedule a discovery work + * for each of them. If the code below fails to allocate needed + * resources, exit without error to keep results of enumeration + * process (if any). + * TODO: Implement restart of dicovery process for all or + * individual discovering mports. + */ + rio_wq = alloc_workqueue("riodisc", 0, 0); + if (!rio_wq) { + pr_err("RIO: unable allocate rio_wq\n"); + goto no_disc; } - if (rio_wq) { - pr_debug("RIO: flush discovery workqueue\n"); - flush_workqueue(rio_wq); - pr_debug("RIO: flush discovery workqueue finished\n"); + work = kcalloc(n, sizeof *work, GFP_KERNEL); + if (!work) { + pr_err("RIO: no memory for work struct\n"); destroy_workqueue(rio_wq); + goto no_disc; } + n = 0; + list_for_each_entry(port, &rio_mports, node) { + if (port->host_deviceid < 0) { + work[n].mport = port; + INIT_WORK(&work[n].work, disc_work_handler); + queue_work(rio_wq, &work[n].work); + n++; + } + } + + flush_workqueue(rio_wq); + pr_debug("RIO: destroy discovery workqueue\n"); + destroy_workqueue(rio_wq); + kfree(work); + +no_disc: rio_init(); return 0; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e069f176a82d..19c03ab2bdcb 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -59,6 +59,7 @@ comment "RTC interfaces" config RTC_INTF_SYSFS boolean "/sys/class/rtc/rtcN (sysfs)" depends on SYSFS + default RTC_CLASS help Say yes here if you want to use your RTCs using sysfs interfaces, /sys/class/rtc/rtc0 through /sys/.../rtcN. @@ -68,6 +69,7 @@ config RTC_INTF_SYSFS config RTC_INTF_PROC boolean "/proc/driver/rtc (procfs for rtcN)" depends on PROC_FS + default RTC_CLASS help Say yes here if you want to use your system clock RTC through the proc interface, /proc/driver/rtc. @@ -79,6 +81,7 @@ config RTC_INTF_PROC config RTC_INTF_DEV boolean "/dev/rtcN (character devices)" + default RTC_CLASS help Say yes here if you want to use your RTCs using the /dev interfaces, which "udev" sets up as /dev/rtc0 through diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index b7c326f7a6d0..342d7d9c0997 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -165,6 +165,16 @@ bfa_com_phy_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) bfa_phy_memclaim(phy, phy_dma->kva_curp, phy_dma->dma_curp, mincfg); } +static void +bfa_com_fru_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) +{ + struct bfa_fru_s *fru = BFA_FRU(bfa); + struct bfa_mem_dma_s *fru_dma = BFA_MEM_FRU_DMA(bfa); + + bfa_fru_attach(fru, &bfa->ioc, bfa, bfa->trcmod, mincfg); + bfa_fru_memclaim(fru, fru_dma->kva_curp, fru_dma->dma_curp, mincfg); +} + /* * BFA IOC FC related definitions */ @@ -274,6 +284,15 @@ bfa_iocfc_sm_initing(struct bfa_iocfc_s *iocfc, enum iocfc_event event) case IOCFC_E_IOC_ENABLED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_read); break; + + case IOCFC_E_DISABLE: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); + break; + + case IOCFC_E_STOP: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping); + break; + case IOCFC_E_IOC_FAILED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed); break; @@ -298,6 +317,15 @@ bfa_iocfc_sm_dconf_read(struct bfa_iocfc_s *iocfc, enum iocfc_event event) case IOCFC_E_DCONF_DONE: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_cfg_wait); break; + + case IOCFC_E_DISABLE: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); + break; + + case IOCFC_E_STOP: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping); + break; + case IOCFC_E_IOC_FAILED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed); break; @@ -322,6 +350,15 @@ bfa_iocfc_sm_init_cfg_wait(struct bfa_iocfc_s *iocfc, enum iocfc_event event) case IOCFC_E_CFG_DONE: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_cfg_done); break; + + case IOCFC_E_DISABLE: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); + break; + + case IOCFC_E_STOP: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping); + break; + case IOCFC_E_IOC_FAILED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed); break; @@ -433,6 +470,12 @@ bfa_iocfc_sm_stopping(struct bfa_iocfc_s *iocfc, enum iocfc_event event) bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb, iocfc->bfa); break; + + case IOCFC_E_IOC_ENABLED: + case IOCFC_E_DCONF_DONE: + case IOCFC_E_CFG_DONE: + break; + default: bfa_sm_fault(iocfc->bfa, event); break; @@ -454,6 +497,15 @@ bfa_iocfc_sm_enabling(struct bfa_iocfc_s *iocfc, enum iocfc_event event) case IOCFC_E_IOC_ENABLED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_cfg_wait); break; + + case IOCFC_E_DISABLE: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); + break; + + case IOCFC_E_STOP: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write); + break; + case IOCFC_E_IOC_FAILED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed); @@ -493,6 +545,13 @@ bfa_iocfc_sm_cfg_wait(struct bfa_iocfc_s *iocfc, enum iocfc_event event) bfa_iocfc_enable_cb, iocfc->bfa); iocfc->bfa->iocfc.cb_reqd = BFA_FALSE; break; + case IOCFC_E_DISABLE: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); + break; + + case IOCFC_E_STOP: + bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write); + break; case IOCFC_E_IOC_FAILED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed); if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE) @@ -524,6 +583,10 @@ bfa_iocfc_sm_disabling(struct bfa_iocfc_s *iocfc, enum iocfc_event event) case IOCFC_E_IOC_DISABLED: bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabled); break; + case IOCFC_E_IOC_ENABLED: + case IOCFC_E_DCONF_DONE: + case IOCFC_E_CFG_DONE: + break; default: bfa_sm_fault(iocfc->bfa, event); break; @@ -785,19 +848,20 @@ void bfa_isr_enable(struct bfa_s *bfa) { u32 umsk; - int pci_func = bfa_ioc_pcifn(&bfa->ioc); + int port_id = bfa_ioc_portid(&bfa->ioc); - bfa_trc(bfa, pci_func); + bfa_trc(bfa, bfa_ioc_pcifn(&bfa->ioc)); + bfa_trc(bfa, port_id); bfa_msix_ctrl_install(bfa); if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { umsk = __HFN_INT_ERR_MASK_CT2; - umsk |= pci_func == 0 ? + umsk |= port_id == 0 ? __HFN_INT_FN0_MASK_CT2 : __HFN_INT_FN1_MASK_CT2; } else { umsk = __HFN_INT_ERR_MASK; - umsk |= pci_func == 0 ? __HFN_INT_FN0_MASK : __HFN_INT_FN1_MASK; + umsk |= port_id == 0 ? __HFN_INT_FN0_MASK : __HFN_INT_FN1_MASK; } writel(umsk, bfa->iocfc.bfa_regs.intr_status); @@ -930,7 +994,8 @@ bfa_iocfc_send_cfg(void *bfa_arg) cfg_info->single_msix_vec = 1; cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; cfg_info->num_cqs = cfg->fwcfg.num_cqs; - cfg_info->num_ioim_reqs = cpu_to_be16(cfg->fwcfg.num_ioim_reqs); + cfg_info->num_ioim_reqs = cpu_to_be16(bfa_fcpim_get_throttle_cfg(bfa, + cfg->fwcfg.num_ioim_reqs)); cfg_info->num_fwtio_reqs = cpu_to_be16(cfg->fwcfg.num_fwtio_reqs); bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); @@ -1192,10 +1257,14 @@ bfa_iocfc_qreg(struct bfa_s *bfa, struct bfi_iocfc_qreg_s *qreg) static void bfa_iocfc_res_recfg(struct bfa_s *bfa, struct bfa_iocfc_fwcfg_s *fwcfg) { + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo; + bfa_fcxp_res_recfg(bfa, fwcfg->num_fcxp_reqs); bfa_uf_res_recfg(bfa, fwcfg->num_uf_bufs); bfa_rport_res_recfg(bfa, fwcfg->num_rports); - bfa_fcp_res_recfg(bfa, fwcfg->num_ioim_reqs); + bfa_fcp_res_recfg(bfa, cpu_to_be16(cfg_info->num_ioim_reqs), + fwcfg->num_ioim_reqs); bfa_tskim_res_recfg(bfa, fwcfg->num_tskim_reqs); } @@ -1693,6 +1762,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); + struct bfa_mem_dma_s *fru_dma = BFA_MEM_FRU_DMA(bfa); WARN_ON((cfg == NULL) || (meminfo == NULL)); @@ -1717,6 +1787,8 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo()); bfa_mem_dma_setup(meminfo, phy_dma, bfa_phy_meminfo(cfg->drvcfg.min_cfg)); + bfa_mem_dma_setup(meminfo, fru_dma, + bfa_fru_meminfo(cfg->drvcfg.min_cfg)); } /* @@ -1789,6 +1861,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg); bfa_com_diag_attach(bfa); bfa_com_phy_attach(bfa, cfg->drvcfg.min_cfg); + bfa_com_fru_attach(bfa, cfg->drvcfg.min_cfg); } /* diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h index b5a1595cc0a5..0efdf312b42c 100644 --- a/drivers/scsi/bfa/bfa_defs.h +++ b/drivers/scsi/bfa/bfa_defs.h @@ -159,10 +159,13 @@ enum bfa_status { BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */ BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */ BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */ + BFA_STATUS_ERROR_TRL_ENABLED = 87, /* TRL is enabled */ + BFA_STATUS_ERROR_QOS_ENABLED = 88, /* QoS is enabled */ BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */ BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact support */ BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */ BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */ + BFA_STATUS_CMD_NOTSUPP_CNA = 146, /* Command not supported for CNA */ BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot * configuration */ BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */ @@ -184,6 +187,17 @@ enum bfa_status { BFA_STATUS_FAA_ACQ_ADDR = 200, /* Acquiring addr */ BFA_STATUS_ERROR_TRUNK_ENABLED = 203, /* Trunk enabled on adapter */ BFA_STATUS_MAX_ENTRY_REACHED = 212, /* MAX entry reached */ + BFA_STATUS_TOPOLOGY_LOOP = 230, /* Topology is set to Loop */ + BFA_STATUS_LOOP_UNSUPP_MEZZ = 231, /* Loop topology is not supported + * on mezz cards */ + BFA_STATUS_INVALID_BW = 233, /* Invalid bandwidth value */ + BFA_STATUS_QOS_BW_INVALID = 234, /* Invalid QOS bandwidth + * configuration */ + BFA_STATUS_DPORT_ENABLED = 235, /* D-port mode is already enabled */ + BFA_STATUS_DPORT_DISABLED = 236, /* D-port mode is already disabled */ + BFA_STATUS_CMD_NOTSUPP_MEZZ = 239, /* Cmd not supported for MEZZ card */ + BFA_STATUS_FRU_NOT_PRESENT = 240, /* fru module not present */ + BFA_STATUS_DPORT_ERR = 245, /* D-port mode is enabled */ BFA_STATUS_MAX_VAL /* Unknown error code */ }; #define bfa_status_t enum bfa_status @@ -249,6 +263,10 @@ struct bfa_adapter_attr_s { u8 is_mezz; u8 trunk_capable; + u8 mfg_day; /* manufacturing day */ + u8 mfg_month; /* manufacturing month */ + u16 mfg_year; /* manufacturing year */ + u16 rsvd; }; /* @@ -499,6 +517,17 @@ struct bfa_ioc_aen_data_s { }; /* + * D-port states + * +*/ +enum bfa_dport_state { + BFA_DPORT_ST_DISABLED = 0, /* D-port is Disabled */ + BFA_DPORT_ST_DISABLING = 1, /* D-port is Disabling */ + BFA_DPORT_ST_ENABLING = 2, /* D-port is Enabling */ + BFA_DPORT_ST_ENABLED = 3, /* D-port is Enabled */ +}; + +/* * ---------------------- mfg definitions ------------ */ @@ -722,7 +751,8 @@ struct bfa_ablk_cfg_pf_s { u8 rsvd[1]; u16 num_qpairs; u16 num_vectors; - u32 bw; + u16 bw_min; + u16 bw_max; }; struct bfa_ablk_cfg_port_s { @@ -889,11 +919,40 @@ struct sfp_diag_ext_s { u8 ext_status_ctl[2]; }; +/* + * Diagnostic: Data Fields -- Address A2h + * General Use Fields: User Writable Table - Features's Control Registers + * Total 32 bytes + */ +struct sfp_usr_eeprom_s { + u8 rsvd1[2]; /* 128-129 */ + u8 ewrap; /* 130 */ + u8 rsvd2[2]; /* */ + u8 owrap; /* 133 */ + u8 rsvd3[2]; /* */ + u8 prbs; /* 136: PRBS 7 generator */ + u8 rsvd4[2]; /* */ + u8 tx_eqz_16; /* 139: TX Equalizer (16xFC) */ + u8 tx_eqz_8; /* 140: TX Equalizer (8xFC) */ + u8 rsvd5[2]; /* */ + u8 rx_emp_16; /* 143: RX Emphasis (16xFC) */ + u8 rx_emp_8; /* 144: RX Emphasis (8xFC) */ + u8 rsvd6[2]; /* */ + u8 tx_eye_adj; /* 147: TX eye Threshold Adjust */ + u8 rsvd7[3]; /* */ + u8 tx_eye_qctl; /* 151: TX eye Quality Control */ + u8 tx_eye_qres; /* 152: TX eye Quality Result */ + u8 rsvd8[2]; /* */ + u8 poh[3]; /* 155-157: Power On Hours */ + u8 rsvd9[2]; /* */ +}; + struct sfp_mem_s { struct sfp_srlid_base_s srlid_base; struct sfp_srlid_ext_s srlid_ext; struct sfp_diag_base_s diag_base; struct sfp_diag_ext_s diag_ext; + struct sfp_usr_eeprom_s usr_eeprom; }; /* diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h index 36756ce0e58f..ec03c8cd8dac 100644 --- a/drivers/scsi/bfa/bfa_defs_svc.h +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -258,6 +258,7 @@ struct bfa_fw_port_lksm_stats_s { u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ u32 bbsc_lr; /* LKSM LR tx for credit recovery */ + u32 rsvd; }; struct bfa_fw_port_snsm_stats_s { @@ -270,6 +271,9 @@ struct bfa_fw_port_snsm_stats_s { u32 sync_lost; /* Sync loss count */ u32 sig_lost; /* Signal loss count */ u32 asn8g_attempts; /* SNSM HWSM at 8Gbps attempts */ + u32 adapt_success; /* SNSM adaptation success */ + u32 adapt_fails; /* SNSM adaptation failures */ + u32 adapt_ign_fails; /* SNSM adaptation failures ignored */ }; struct bfa_fw_port_physm_stats_s { @@ -324,12 +328,46 @@ struct bfa_fw_fcoe_port_stats_s { struct bfa_fw_fip_stats_s fip_stats; }; +/** + * @brief LPSM statistics + */ +struct bfa_fw_lpsm_stats_s { + u32 cls_rx; /* LPSM cls_rx */ + u32 cls_tx; /* LPSM cls_tx */ + u32 arbf0_rx; /* LPSM abrf0 rcvd */ + u32 arbf0_tx; /* LPSM abrf0 xmit */ + u32 init_rx; /* LPSM loop init start */ + u32 unexp_hwst; /* LPSM unknown hw state */ + u32 unexp_frame; /* LPSM unknown_frame */ + u32 unexp_prim; /* LPSM unexpected primitive */ + u32 prev_alpa_unavail; /* LPSM prev alpa unavailable */ + u32 alpa_unavail; /* LPSM alpa not available */ + u32 lip_rx; /* LPSM lip rcvd */ + u32 lip_f7f7_rx; /* LPSM lip f7f7 rcvd */ + u32 lip_f8_rx; /* LPSM lip f8 rcvd */ + u32 lip_f8f7_rx; /* LPSM lip f8f7 rcvd */ + u32 lip_other_rx; /* LPSM lip other rcvd */ + u32 lip_tx; /* LPSM lip xmit */ + u32 retry_tov; /* LPSM retry TOV */ + u32 lip_tov; /* LPSM LIP wait TOV */ + u32 idle_tov; /* LPSM idle wait TOV */ + u32 arbf0_tov; /* LPSM arbfo wait TOV */ + u32 stop_loop_tov; /* LPSM stop loop wait TOV */ + u32 lixa_tov; /* LPSM lisa wait TOV */ + u32 lixx_tov; /* LPSM lilp/lirp wait TOV */ + u32 cls_tov; /* LPSM cls wait TOV */ + u32 sler; /* LPSM SLER recvd */ + u32 failed; /* LPSM failed */ + u32 success; /* LPSM online */ +}; + /* * IOC firmware FC uport stats */ struct bfa_fw_fc_uport_stats_s { struct bfa_fw_port_snsm_stats_s snsm_stats; struct bfa_fw_port_lksm_stats_s lksm_stats; + struct bfa_fw_lpsm_stats_s lpsm_stats; }; /* @@ -357,11 +395,6 @@ struct bfa_fw_fcxchg_stats_s { u32 ua_state_inv; }; -struct bfa_fw_lpsm_stats_s { - u32 cls_rx; - u32 cls_tx; -}; - /* * Trunk statistics */ @@ -454,7 +487,6 @@ struct bfa_fw_stats_s { struct bfa_fw_io_stats_s io_stats; struct bfa_fw_port_stats_s port_stats; struct bfa_fw_fcxchg_stats_s fcxchg_stats; - struct bfa_fw_lpsm_stats_s lpsm_stats; struct bfa_fw_lps_stats_s lps_stats; struct bfa_fw_trunk_stats_s trunk_stats; struct bfa_fw_advsm_stats_s advsm_stats; @@ -494,13 +526,23 @@ enum bfa_qos_bw_alloc { BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */ }; #pragma pack(1) + +struct bfa_qos_bw_s { + u8 qos_bw_set; + u8 high; + u8 med; + u8 low; +}; + /* * QoS attribute returned in QoS Query */ struct bfa_qos_attr_s { - u8 state; /* QoS current state */ - u8 rsvd[3]; - u32 total_bb_cr; /* Total BB Credits */ + u8 state; /* QoS current state */ + u8 rsvd1[3]; + u32 total_bb_cr; /* Total BB Credits */ + struct bfa_qos_bw_s qos_bw; /* QOS bw cfg */ + struct bfa_qos_bw_s qos_bw_op; /* QOS bw operational */ }; /* @@ -692,7 +734,8 @@ enum bfa_port_states { BFA_PORT_ST_FWMISMATCH = 12, BFA_PORT_ST_PREBOOT_DISABLED = 13, BFA_PORT_ST_TOGGLING_QWAIT = 14, - BFA_PORT_ST_ACQ_ADDR = 15, + BFA_PORT_ST_FAA_MISCONFIG = 15, + BFA_PORT_ST_DPORT = 16, BFA_PORT_ST_MAX_STATE, }; @@ -714,9 +757,11 @@ enum bfa_port_type { */ enum bfa_port_topology { BFA_PORT_TOPOLOGY_NONE = 0, /* No valid topology */ - BFA_PORT_TOPOLOGY_P2P = 1, /* P2P only */ - BFA_PORT_TOPOLOGY_LOOP = 2, /* LOOP topology */ - BFA_PORT_TOPOLOGY_AUTO = 3, /* auto topology selection */ + BFA_PORT_TOPOLOGY_P2P_OLD_VER = 1, /* P2P def for older ver */ + BFA_PORT_TOPOLOGY_LOOP = 2, /* LOOP topology */ + BFA_PORT_TOPOLOGY_AUTO_OLD_VER = 3, /* auto def for older ver */ + BFA_PORT_TOPOLOGY_AUTO = 4, /* auto topology selection */ + BFA_PORT_TOPOLOGY_P2P = 5, /* P2P only */ }; /* @@ -760,6 +805,7 @@ enum bfa_port_linkstate_rsn { BFA_PORT_LINKSTATE_RSN_LOCAL_FAULT = 9, BFA_PORT_LINKSTATE_RSN_REMOTE_FAULT = 10, BFA_PORT_LINKSTATE_RSN_TIMEOUT = 11, + BFA_PORT_LINKSTATE_RSN_FAA_MISCONFIG = 12, @@ -833,6 +879,19 @@ struct bfa_lunmask_cfg_s { struct bfa_lun_mask_s lun_list[MAX_LUN_MASK_CFG]; }; +struct bfa_throttle_cfg_s { + u16 is_valid; + u16 value; + u32 rsvd; +}; + +struct bfa_defs_fcpim_throttle_s { + u16 max_value; + u16 cur_value; + u16 cfg_value; + u16 rsvd; +}; + /* * Physical port configuration */ @@ -851,9 +910,10 @@ struct bfa_port_cfg_s { u8 bb_scn; /* BB_SCN value from FLOGI Exchg */ u8 bb_scn_state; /* Config state of BB_SCN */ u8 faa_state; /* FAA enabled/disabled */ - u8 rsvd[1]; + u8 rsvd1; u16 path_tov; /* device path timeout */ u16 q_depth; /* SCSI Queue depth */ + struct bfa_qos_bw_s qos_bw; /* QOS bandwidth */ }; #pragma pack() @@ -901,7 +961,7 @@ struct bfa_port_attr_s { /* FCoE specific */ u16 fcoe_vlan; - u8 rsvd1[2]; + u8 rsvd1[6]; }; /* @@ -971,6 +1031,13 @@ struct bfa_trunk_vc_attr_s { u16 vc_credits[8]; }; +struct bfa_fcport_loop_info_s { + u8 myalpa; /* alpa claimed */ + u8 alpabm_val; /* alpa bitmap valid or not (1 or 0) */ + u8 resvd[6]; + struct fc_alpabm_s alpabm; /* alpa bitmap */ +}; + /* * Link state information */ @@ -981,13 +1048,18 @@ struct bfa_port_link_s { u8 speed; /* Link speed (1/2/4/8 G) */ u32 linkstate_opt; /* Linkstate optional data (debug) */ u8 trunked; /* Trunked or not (1 or 0) */ - u8 resvd[3]; + u8 resvd[7]; struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ union { - struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ - struct bfa_trunk_vc_attr_s trunk_vc_attr; - struct bfa_fcport_fcf_s fcf; /* FCF information (for FCoE) */ - } vc_fcf; + struct bfa_fcport_loop_info_s loop_info; + union { + struct bfa_qos_vc_attr_s qos_vc_attr; + /* VC info from ELP */ + struct bfa_trunk_vc_attr_s trunk_vc_attr; + struct bfa_fcport_fcf_s fcf; + /* FCF information (for FCoE) */ + } vc_fcf; + } attr; }; #pragma pack() @@ -1112,6 +1184,9 @@ struct bfa_port_fc_stats_s { u64 tx_frames; /* Tx frames */ u64 tx_words; /* Tx words */ u64 tx_lip; /* Tx LIP */ + u64 tx_lip_f7f7; /* Tx LIP_F7F7 */ + u64 tx_lip_f8f7; /* Tx LIP_F8F7 */ + u64 tx_arbf0; /* Tx ARB F0 */ u64 tx_nos; /* Tx NOS */ u64 tx_ols; /* Tx OLS */ u64 tx_lr; /* Tx LR */ @@ -1119,6 +1194,9 @@ struct bfa_port_fc_stats_s { u64 rx_frames; /* Rx frames */ u64 rx_words; /* Rx words */ u64 lip_count; /* Rx LIP */ + u64 rx_lip_f7f7; /* Rx LIP_F7F7 */ + u64 rx_lip_f8f7; /* Rx LIP_F8F7 */ + u64 rx_arbf0; /* Rx ARB F0 */ u64 nos_count; /* Rx NOS */ u64 ols_count; /* Rx OLS */ u64 lr_count; /* Rx LR */ @@ -1140,6 +1218,7 @@ struct bfa_port_fc_stats_s { u64 bbsc_frames_lost; /* Credit Recovery-Frames Lost */ u64 bbsc_credits_lost; /* Credit Recovery-Credits Lost */ u64 bbsc_link_resets; /* Credit Recovery-Link Resets */ + u64 loop_timeouts; /* Loop timeouts */ }; /* diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h index e0beb4d7e264..bea821b98030 100644 --- a/drivers/scsi/bfa/bfa_fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -24,6 +24,7 @@ typedef u64 wwn_t; #define WWN_NULL (0) #define FC_SYMNAME_MAX 256 /* max name server symbolic name size */ +#define FC_ALPA_MAX 128 #pragma pack(1) @@ -1015,6 +1016,10 @@ struct fc_symname_s { u8 symname[FC_SYMNAME_MAX]; }; +struct fc_alpabm_s { + u8 alpa_bm[FC_ALPA_MAX / 8]; +}; + /* * protocol default timeout values */ diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c index 273cee90b3b4..dce787f6cca2 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.c +++ b/drivers/scsi/bfa/bfa_fcbuild.c @@ -228,6 +228,10 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s)); + /* For FC AL bb_cr is 0 and altbbcred is 1 */ + if (!bb_cr) + plogi->csp.altbbcred = 1; + plogi->els_cmd.els_code = els_code; if (els_code == FC_ELS_PLOGI) fc_els_req_build(fchs, d_id, s_id, ox_id); diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 1633963c66ca..27b560962357 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -158,6 +158,7 @@ enum bfa_tskim_event { BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */ BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */ BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */ + BFA_TSKIM_SM_UTAG = 10, /* TM completion unknown tag */ }; /* @@ -3036,7 +3037,7 @@ bfa_ioim_abort(struct bfa_ioim_s *ioim) static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_START: @@ -3074,7 +3075,7 @@ bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_DONE: @@ -3110,7 +3111,7 @@ bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_DONE: @@ -3119,6 +3120,7 @@ bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) */ break; + case BFA_TSKIM_SM_UTAG: case BFA_TSKIM_SM_CLEANUP_DONE: bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); bfa_tskim_cleanup_ios(tskim); @@ -3138,7 +3140,7 @@ bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_IOS_DONE: @@ -3170,7 +3172,7 @@ bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_QRESUME: @@ -3207,7 +3209,7 @@ static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_DONE: @@ -3238,7 +3240,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) { - bfa_trc(tskim->bfa, event); + bfa_trc(tskim->bfa, tskim->tsk_tag << 16 | event); switch (event) { case BFA_TSKIM_SM_HCB: @@ -3560,6 +3562,8 @@ bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) { bfa_stats(tskim->itnim, tm_cleanup_comps); bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE); + } else if (rsp->tsk_status == BFI_TSKIM_STS_UTAG) { + bfa_sm_send_event(tskim, BFA_TSKIM_SM_UTAG); } else { bfa_stats(tskim->itnim, tm_fw_rsps); bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE); @@ -3699,6 +3703,7 @@ bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_mem_dma_s *seg_ptr; u16 idx, nsegs, num_io_req; + fcp->max_ioim_reqs = cfg->fwcfg.num_ioim_reqs; fcp->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; fcp->num_fwtio_reqs = cfg->fwcfg.num_fwtio_reqs; fcp->num_itns = cfg->fwcfg.num_rports; @@ -3721,6 +3726,7 @@ bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_iocfc_set_snsbase(bfa, idx, fcp->snsbase[idx].pa); } + fcp->throttle_update_required = 1; bfa_fcpim_attach(fcp, bfad, cfg, pcidev); bfa_iotag_attach(fcp); @@ -3759,23 +3765,33 @@ bfa_fcp_iocdisable(struct bfa_s *bfa) { struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcp->iotag_unused_q, &fcp->iotag_ioim_free_q); - bfa_fcpim_iocdisable(fcp); } void -bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw) +bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw, u16 max_ioim_fw) { struct bfa_fcp_mod_s *mod = BFA_FCP_MOD(bfa); struct list_head *qe; int i; + /* Update io throttle value only once during driver load time */ + if (!mod->throttle_update_required) + return; + for (i = 0; i < (mod->num_ioim_reqs - num_ioim_fw); i++) { bfa_q_deq_tail(&mod->iotag_ioim_free_q, &qe); list_add_tail(qe, &mod->iotag_unused_q); } + + if (mod->num_ioim_reqs != num_ioim_fw) { + bfa_trc(bfa, mod->num_ioim_reqs); + bfa_trc(bfa, num_ioim_fw); + } + + mod->max_ioim_reqs = max_ioim_fw; + mod->num_ioim_reqs = num_ioim_fw; + mod->throttle_update_required = 0; } void @@ -3833,3 +3849,88 @@ bfa_iotag_attach(struct bfa_fcp_mod_s *fcp) bfa_mem_kva_curp(fcp) = (u8 *) iotag; } + + +/** + * To send config req, first try to use throttle value from flash + * If 0, then use driver parameter + * We need to use min(flash_val, drv_val) because + * memory allocation was done based on this cfg'd value + */ +u16 +bfa_fcpim_get_throttle_cfg(struct bfa_s *bfa, u16 drv_cfg_param) +{ + u16 tmp; + struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); + + /* + * If throttle value from flash is already in effect after driver is + * loaded then until next load, always return current value instead + * of actual flash value + */ + if (!fcp->throttle_update_required) + return (u16)fcp->num_ioim_reqs; + + tmp = bfa_dconf_read_data_valid(bfa) ? bfa_fcpim_read_throttle(bfa) : 0; + if (!tmp || (tmp > drv_cfg_param)) + tmp = drv_cfg_param; + + return tmp; +} + +bfa_status_t +bfa_fcpim_write_throttle(struct bfa_s *bfa, u16 value) +{ + if (!bfa_dconf_get_min_cfg(bfa)) { + BFA_DCONF_MOD(bfa)->dconf->throttle_cfg.value = value; + BFA_DCONF_MOD(bfa)->dconf->throttle_cfg.is_valid = 1; + return BFA_STATUS_OK; + } + + return BFA_STATUS_FAILED; +} + +u16 +bfa_fcpim_read_throttle(struct bfa_s *bfa) +{ + struct bfa_throttle_cfg_s *throttle_cfg = + &(BFA_DCONF_MOD(bfa)->dconf->throttle_cfg); + + return ((!bfa_dconf_get_min_cfg(bfa)) ? + ((throttle_cfg->is_valid == 1) ? (throttle_cfg->value) : 0) : 0); +} + +bfa_status_t +bfa_fcpim_throttle_set(struct bfa_s *bfa, u16 value) +{ + /* in min cfg no commands should run. */ + if ((bfa_dconf_get_min_cfg(bfa) == BFA_TRUE) || + (!bfa_dconf_read_data_valid(bfa))) + return BFA_STATUS_FAILED; + + bfa_fcpim_write_throttle(bfa, value); + + return bfa_dconf_update(bfa); +} + +bfa_status_t +bfa_fcpim_throttle_get(struct bfa_s *bfa, void *buf) +{ + struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_defs_fcpim_throttle_s throttle; + + if ((bfa_dconf_get_min_cfg(bfa) == BFA_TRUE) || + (!bfa_dconf_read_data_valid(bfa))) + return BFA_STATUS_FAILED; + + memset(&throttle, 0, sizeof(struct bfa_defs_fcpim_throttle_s)); + + throttle.cur_value = (u16)(fcpim->fcp->num_ioim_reqs); + throttle.cfg_value = bfa_fcpim_read_throttle(bfa); + if (!throttle.cfg_value) + throttle.cfg_value = throttle.cur_value; + throttle.max_value = (u16)(fcpim->fcp->max_ioim_reqs); + memcpy(buf, &throttle, sizeof(struct bfa_defs_fcpim_throttle_s)); + + return BFA_STATUS_OK; +} diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index 36f26da80f76..e693af6e5930 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -42,7 +42,7 @@ void bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)); void bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m); void bfa_iotag_attach(struct bfa_fcp_mod_s *fcp); -void bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw); +void bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw, u16 max_ioim_fw); #define BFA_FCP_MOD(_hal) (&(_hal)->modules.fcp_mod) #define BFA_MEM_FCP_KVA(__bfa) (&(BFA_FCP_MOD(__bfa)->kva_seg)) @@ -51,7 +51,9 @@ void bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw); #define BFA_ITN_FROM_TAG(_fcp, _tag) \ ((_fcp)->itn_arr + ((_tag) & ((_fcp)->num_itns - 1))) #define BFA_SNSINFO_FROM_TAG(_fcp, _tag) \ - bfa_mem_get_dmabuf_kva(_fcp, _tag, BFI_IOIM_SNSLEN) + bfa_mem_get_dmabuf_kva(_fcp, (_tag & BFA_IOIM_IOTAG_MASK), \ + BFI_IOIM_SNSLEN) + #define BFA_ITNIM_MIN 32 #define BFA_ITNIM_MAX 1024 @@ -148,6 +150,7 @@ struct bfa_fcp_mod_s { struct list_head iotag_unused_q; /* unused IO resources*/ struct bfa_iotag_s *iotag_arr; struct bfa_itn_s *itn_arr; + int max_ioim_reqs; int num_ioim_reqs; int num_fwtio_reqs; int num_itns; @@ -155,6 +158,7 @@ struct bfa_fcp_mod_s { struct bfa_fcpim_s fcpim; struct bfa_mem_dma_s dma_seg[BFA_FCP_DMA_SEGS]; struct bfa_mem_kva_s kva_seg; + int throttle_update_required; }; /* @@ -416,5 +420,10 @@ bfa_status_t bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, bfa_status_t bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun); bfa_status_t bfa_fcpim_lunmask_clear(struct bfa_s *bfa); +u16 bfa_fcpim_read_throttle(struct bfa_s *bfa); +bfa_status_t bfa_fcpim_write_throttle(struct bfa_s *bfa, u16 value); +bfa_status_t bfa_fcpim_throttle_set(struct bfa_s *bfa, u16 value); +bfa_status_t bfa_fcpim_throttle_get(struct bfa_s *bfa, void *buf); +u16 bfa_fcpim_get_throttle_cfg(struct bfa_s *bfa, u16 drv_cfg_param); #endif /* __BFA_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index fd3e84d32bd2..d428808fb37e 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -303,16 +303,30 @@ static void bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event) { + struct bfa_s *bfa = fabric->fcs->bfa; + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); bfa_trc(fabric->fcs, event); switch (event) { case BFA_FCS_FABRIC_SM_START: - if (bfa_fcport_is_linkup(fabric->fcs->bfa)) { + if (!bfa_fcport_is_linkup(fabric->fcs->bfa)) { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + break; + } + if (bfa_fcport_get_topology(bfa) == + BFA_PORT_TOPOLOGY_LOOP) { + fabric->fab_type = BFA_FCS_FABRIC_LOOP; + fabric->bport.pid = bfa_fcport_get_myalpa(bfa); + fabric->bport.pid = bfa_hton3b(fabric->bport.pid); + bfa_sm_set_state(fabric, + bfa_fcs_fabric_sm_online); + bfa_fcs_fabric_set_opertype(fabric); + bfa_fcs_lport_online(&fabric->bport); + } else { bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); bfa_fcs_fabric_login(fabric); - } else - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + } break; case BFA_FCS_FABRIC_SM_LINK_UP: @@ -337,16 +351,28 @@ static void bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event) { + struct bfa_s *bfa = fabric->fcs->bfa; + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); bfa_trc(fabric->fcs, event); switch (event) { case BFA_FCS_FABRIC_SM_LINK_UP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); + if (bfa_fcport_get_topology(bfa) != BFA_PORT_TOPOLOGY_LOOP) { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); + bfa_fcs_fabric_login(fabric); + break; + } + fabric->fab_type = BFA_FCS_FABRIC_LOOP; + fabric->bport.pid = bfa_fcport_get_myalpa(bfa); + fabric->bport.pid = bfa_hton3b(fabric->bport.pid); + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); + bfa_fcs_fabric_set_opertype(fabric); + bfa_fcs_lport_online(&fabric->bport); break; case BFA_FCS_FABRIC_SM_RETRY_OP: + case BFA_FCS_FABRIC_SM_LOOPBACK: break; case BFA_FCS_FABRIC_SM_DELETE: @@ -595,14 +621,20 @@ void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event) { + struct bfa_s *bfa = fabric->fcs->bfa; + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); bfa_trc(fabric->fcs, event); switch (event) { case BFA_FCS_FABRIC_SM_LINK_DOWN: bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_fabric_notify_offline(fabric); + if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) { + bfa_fcs_lport_offline(&fabric->bport); + } else { + bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); + bfa_fcs_fabric_notify_offline(fabric); + } break; case BFA_FCS_FABRIC_SM_DELETE: @@ -719,20 +751,29 @@ static void bfa_fcs_fabric_sm_stopping(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event) { + struct bfa_s *bfa = fabric->fcs->bfa; + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); bfa_trc(fabric->fcs, event); switch (event) { case BFA_FCS_FABRIC_SM_STOPCOMP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_LOGOUT); + if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); + } else { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); + bfa_sm_send_event(fabric->lps, BFA_LPS_SM_LOGOUT); + } break; case BFA_FCS_FABRIC_SM_LINK_UP: break; case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); + if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); + else + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); break; default: @@ -975,9 +1016,6 @@ bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; u8 alpa = 0, bb_scn = 0; - if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) - alpa = bfa_fcport_get_myalpa(bfa); - if (bfa_fcs_fabric_is_bbscn_enabled(fabric) && (!fabric->fcs->bbscn_flogi_rjt)) bb_scn = BFA_FCS_PORT_DEF_BB_SCN; diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 6c4377cb287f..a449706c6bc0 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -118,9 +118,9 @@ struct bfa_fcs_lport_fab_s { #define MAX_ALPA_COUNT 127 struct bfa_fcs_lport_loop_s { - u8 num_alpa; /* Num of ALPA entries in the map */ - u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional - *Map */ + u8 num_alpa; /* Num of ALPA entries in the map */ + u8 alpabm_valid; /* alpa bitmap valid or not (1 or 0) */ + u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional Map */ struct bfa_fcs_lport_s *port; /* parent port */ }; @@ -175,6 +175,7 @@ enum bfa_fcs_fabric_type { BFA_FCS_FABRIC_UNKNOWN = 0, BFA_FCS_FABRIC_SWITCHED = 1, BFA_FCS_FABRIC_N2N = 2, + BFA_FCS_FABRIC_LOOP = 3, }; @@ -350,9 +351,10 @@ void bfa_fcs_lport_ns_util_send_rspn_id(void *cbarg, struct bfa_fcxp_s *fcxp_alloced); void bfa_fcs_lport_scn_init(struct bfa_fcs_lport_s *vport); void bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_fab_scn_online(struct bfa_fcs_lport_s *vport); void bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, struct fchs_s *rx_frame, u32 len); +void bfa_fcs_lport_lip_scn_online(bfa_fcs_lport_t *port); struct bfa_fcs_vport_s { struct list_head qe; /* queue elem */ @@ -453,6 +455,7 @@ struct bfa_fcs_rport_s { struct bfa_rport_stats_s stats; /* rport stats */ enum bfa_rport_function scsi_function; /* Initiator/Target */ struct bfa_fcs_rpf_s rpf; /* Rport features module */ + bfa_boolean_t scn_online; /* SCN online flag */ }; static inline struct bfa_rport_s * @@ -639,9 +642,9 @@ struct bfa_fcs_fdmi_hba_attr_s { u8 model[16]; u8 model_desc[256]; u8 hw_version[8]; - u8 driver_version[8]; + u8 driver_version[BFA_VERSION_LEN]; u8 option_rom_ver[BFA_VERSION_LEN]; - u8 fw_version[8]; + u8 fw_version[BFA_VERSION_LEN]; u8 os_name[256]; __be32 max_ct_pyld; }; @@ -733,7 +736,7 @@ enum rport_event { RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */ RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */ RPSM_EVENT_DELETE = 7, /* RPORT delete request */ - RPSM_EVENT_SCN = 8, /* state change notification */ + RPSM_EVENT_FAB_SCN = 8, /* state change notification */ RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */ RPSM_EVENT_FAILED = 10, /* Request to rport failed. */ RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */ @@ -744,7 +747,9 @@ enum rport_event { RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continuously */ - RPSM_EVENT_FC4_FCS_ONLINE = 19, /*!< FC-4 FCS online complete */ + RPSM_EVENT_SCN_OFFLINE = 19, /* loop scn offline */ + RPSM_EVENT_SCN_ONLINE = 20, /* loop scn online */ + RPSM_EVENT_FC4_FCS_ONLINE = 21, /* FC-4 FCS online complete */ }; /* @@ -763,7 +768,7 @@ enum bfa_fcs_itnim_event { BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */ - BFA_FCS_ITNIM_SM_HAL_ONLINE = 13, /*!< bfa rport online event */ + BFA_FCS_ITNIM_SM_HAL_ONLINE = 13, /* bfa rport online event */ }; /* diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 3b75f6fb2de1..1224d0462a49 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -23,6 +23,34 @@ BFA_TRC_FILE(FCS, PORT); +/* + * ALPA to LIXA bitmap mapping + * + * ALPA 0x00 (Word 0, Bit 30) is invalid for N_Ports. Also Word 0 Bit 31 + * is for L_bit (login required) and is filled as ALPA 0x00 here. + */ +static const u8 loop_alpa_map[] = { + 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, /* Word 0 Bits 31..24 */ + 0x17, 0x18, 0x1B, 0x1D, 0x1E, 0x1F, 0x23, 0x25, /* Word 0 Bits 23..16 */ + 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, /* Word 0 Bits 15..08 */ + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x39, 0x3A, /* Word 0 Bits 07..00 */ + + 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, /* Word 1 Bits 31..24 */ + 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 0x55, /* Word 1 Bits 23..16 */ + 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, /* Word 1 Bits 15..08 */ + 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, /* Word 1 Bits 07..00 */ + + 0x73, 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, /* Word 2 Bits 31..24 */ + 0x81, 0x82, 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, /* Word 2 Bits 23..16 */ + 0x9B, 0x9D, 0x9E, 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, /* Word 2 Bits 15..08 */ + 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xB1, 0xB2, /* Word 2 Bits 07..00 */ + + 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 0xBA, 0xBC, 0xC3, /* Word 3 Bits 31..24 */ + 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, /* Word 3 Bits 23..16 */ + 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD9, /* Word 3 Bits 15..08 */ + 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF, /* Word 3 Bits 07..00 */ +}; + static void bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl); @@ -51,6 +79,10 @@ static void bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port); static void bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port); static void bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_loop_init(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_loop_online(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_loop_offline(struct bfa_fcs_lport_s *port); + static struct { void (*init) (struct bfa_fcs_lport_s *port); void (*online) (struct bfa_fcs_lport_s *port); @@ -62,7 +94,9 @@ static struct { bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online, bfa_fcs_lport_fab_offline}, { bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online, - bfa_fcs_lport_n2n_offline}, + bfa_fcs_lport_n2n_offline}, { + bfa_fcs_lport_loop_init, bfa_fcs_lport_loop_online, + bfa_fcs_lport_loop_offline}, }; /* @@ -1127,7 +1161,7 @@ static void bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port) { bfa_fcs_lport_ns_online(port); - bfa_fcs_lport_scn_online(port); + bfa_fcs_lport_fab_scn_online(port); } /* @@ -1221,6 +1255,98 @@ bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port) n2n_port->reply_oxid = 0; } +void +bfa_fcport_get_loop_attr(struct bfa_fcs_lport_s *port) +{ + int i = 0, j = 0, bit = 0, alpa_bit = 0; + u8 k = 0; + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(port->fcs->bfa); + + port->port_topo.ploop.alpabm_valid = fcport->alpabm_valid; + port->pid = fcport->myalpa; + port->pid = bfa_hton3b(port->pid); + + for (i = 0; i < (FC_ALPA_MAX / 8); i++) { + for (j = 0, alpa_bit = 0; j < 8; j++, alpa_bit++) { + bfa_trc(port->fcs->bfa, fcport->alpabm.alpa_bm[i]); + bit = (fcport->alpabm.alpa_bm[i] & (1 << (7 - j))); + if (bit) { + port->port_topo.ploop.alpa_pos_map[k] = + loop_alpa_map[(i * 8) + alpa_bit]; + k++; + bfa_trc(port->fcs->bfa, k); + bfa_trc(port->fcs->bfa, + port->port_topo.ploop.alpa_pos_map[k]); + } + } + } + port->port_topo.ploop.num_alpa = k; +} + +/* + * Called by fcs/port to initialize Loop topology. + */ +static void +bfa_fcs_lport_loop_init(struct bfa_fcs_lport_s *port) +{ +} + +/* + * Called by fcs/port to notify transition to online state. + */ +static void +bfa_fcs_lport_loop_online(struct bfa_fcs_lport_s *port) +{ + u8 num_alpa = 0, alpabm_valid = 0; + struct bfa_fcs_rport_s *rport; + u8 *alpa_map = NULL; + int i = 0; + u32 pid; + + bfa_fcport_get_loop_attr(port); + + num_alpa = port->port_topo.ploop.num_alpa; + alpabm_valid = port->port_topo.ploop.alpabm_valid; + alpa_map = port->port_topo.ploop.alpa_pos_map; + + bfa_trc(port->fcs->bfa, port->pid); + bfa_trc(port->fcs->bfa, num_alpa); + if (alpabm_valid == 1) { + for (i = 0; i < num_alpa; i++) { + bfa_trc(port->fcs->bfa, alpa_map[i]); + if (alpa_map[i] != bfa_hton3b(port->pid)) { + pid = alpa_map[i]; + bfa_trc(port->fcs->bfa, pid); + rport = bfa_fcs_lport_get_rport_by_pid(port, + bfa_hton3b(pid)); + if (!rport) + rport = bfa_fcs_rport_create(port, + bfa_hton3b(pid)); + } + } + } else { + for (i = 0; i < MAX_ALPA_COUNT; i++) { + if (alpa_map[i] != port->pid) { + pid = loop_alpa_map[i]; + bfa_trc(port->fcs->bfa, pid); + rport = bfa_fcs_lport_get_rport_by_pid(port, + bfa_hton3b(pid)); + if (!rport) + rport = bfa_fcs_rport_create(port, + bfa_hton3b(pid)); + } + } + } +} + +/* + * Called by fcs/port to notify transition to offline state. + */ +static void +bfa_fcs_lport_loop_offline(struct bfa_fcs_lport_s *port) +{ +} + #define BFA_FCS_FDMI_CMD_MAX_RETRIES 2 /* @@ -1888,13 +2014,10 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) sizeof(templen)); } - /* - * f/w Version = driver version - */ attr = (struct fdmi_attr_s *) curr_ptr; attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION); - templen = (u16) strlen(fcs_hba_attr->driver_version); - memcpy(attr->value, fcs_hba_attr->driver_version, templen); + templen = (u16) strlen(fcs_hba_attr->fw_version); + memcpy(attr->value, fcs_hba_attr->fw_version, templen); templen = fc_roundup(templen, sizeof(u32)); curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; len += templen; @@ -2296,6 +2419,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, { struct bfa_fcs_lport_s *port = fdmi->ms->port; struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; + struct bfa_fcs_fdmi_port_attr_s fcs_port_attr; memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s)); @@ -2331,7 +2455,9 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, sizeof(driver_info->host_os_patch)); } - hba_attr->max_ct_pyld = cpu_to_be32(FC_MAX_PDUSZ); + /* Retrieve the max frame size from the port attr */ + bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr); + hba_attr->max_ct_pyld = fcs_port_attr.max_frm_size; } static void @@ -2391,7 +2517,7 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, /* * Max PDU Size. */ - port_attr->max_frm_size = cpu_to_be32(FC_MAX_PDUSZ); + port_attr->max_frm_size = cpu_to_be32(pport_attr.pport_cfg.maxfrsize); /* * OS device Name @@ -5199,7 +5325,7 @@ bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *port) } void -bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *port) +bfa_fcs_lport_fab_scn_online(struct bfa_fcs_lport_s *port) { struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); @@ -5621,6 +5747,15 @@ bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port) } /* + * Let new loop map create missing rports + */ +void +bfa_fcs_lport_lip_scn_online(struct bfa_fcs_lport_s *port) +{ + bfa_fcs_lport_loop_online(port); +} + +/* * FCS virtual port state machine */ diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index cc43b2a58ce3..58ac643ba9f3 100644 --- a/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -106,9 +106,13 @@ static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, enum rport_event event); static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_adisc_online_sending( + struct bfa_fcs_rport_s *rport, enum rport_event event); +static void bfa_fcs_rport_sm_adisc_online(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_adisc_offline_sending(struct bfa_fcs_rport_s + *rport, enum rport_event event); +static void bfa_fcs_rport_sm_adisc_offline(struct bfa_fcs_rport_s *rport, enum rport_event event); static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, enum rport_event event); @@ -150,8 +154,10 @@ static struct bfa_sm_table_s rport_sm_table[] = { {BFA_SM(bfa_fcs_rport_sm_online), BFA_RPORT_ONLINE}, {BFA_SM(bfa_fcs_rport_sm_nsquery_sending), BFA_RPORT_NSQUERY}, {BFA_SM(bfa_fcs_rport_sm_nsquery), BFA_RPORT_NSQUERY}, - {BFA_SM(bfa_fcs_rport_sm_adisc_sending), BFA_RPORT_ADISC}, - {BFA_SM(bfa_fcs_rport_sm_adisc), BFA_RPORT_ADISC}, + {BFA_SM(bfa_fcs_rport_sm_adisc_online_sending), BFA_RPORT_ADISC}, + {BFA_SM(bfa_fcs_rport_sm_adisc_online), BFA_RPORT_ADISC}, + {BFA_SM(bfa_fcs_rport_sm_adisc_offline_sending), BFA_RPORT_ADISC}, + {BFA_SM(bfa_fcs_rport_sm_adisc_offline), BFA_RPORT_ADISC}, {BFA_SM(bfa_fcs_rport_sm_fc4_logorcv), BFA_RPORT_LOGORCV}, {BFA_SM(bfa_fcs_rport_sm_fc4_logosend), BFA_RPORT_LOGO}, {BFA_SM(bfa_fcs_rport_sm_fc4_offline), BFA_RPORT_OFFLINE}, @@ -231,10 +237,19 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_plogiacc(rport, NULL); break; + case RPSM_EVENT_SCN_OFFLINE: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: /* query the NS */ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); + WARN_ON(!(bfa_fcport_get_topology(rport->port->fcs->bfa) != + BFA_PORT_TOPOLOGY_LOOP)); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; bfa_fcs_rport_send_nsdisc(rport, NULL); @@ -280,12 +295,20 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_PLOGI_RCVD: case RPSM_EVENT_PLOGI_COMP: - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: /* * Ignore, SCN is possibly online notification. */ break; + case RPSM_EVENT_SCN_OFFLINE: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; + case RPSM_EVENT_ADDRESS_CHANGE: bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); @@ -346,9 +369,19 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_plogiacc(rport, NULL); break; + case RPSM_EVENT_SCN_OFFLINE: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_timer_stop(&rport->timer); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; + case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: bfa_timer_stop(&rport->timer); + WARN_ON(!(bfa_fcport_get_topology(rport->port->fcs->bfa) != + BFA_PORT_TOPOLOGY_LOOP)); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; bfa_fcs_rport_send_nsdisc(rport, NULL); @@ -422,7 +455,18 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) } break; - case RPSM_EVENT_PLOGI_RETRY: + case RPSM_EVENT_SCN_ONLINE: + break; + + case RPSM_EVENT_SCN_OFFLINE: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_fcxp_discard(rport->fcxp); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; + + case RPSM_EVENT_PLOGI_RETRY: rport->plogi_retries = 0; bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry); bfa_timer_start(rport->fcs->bfa, &rport->timer, @@ -440,8 +484,10 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) break; case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: bfa_fcxp_discard(rport->fcxp); + WARN_ON(!(bfa_fcport_get_topology(rport->port->fcs->bfa) != + BFA_PORT_TOPOLOGY_LOOP)); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; bfa_fcs_rport_send_nsdisc(rport, NULL); @@ -512,7 +558,8 @@ bfa_fcs_rport_sm_fc4_fcs_online(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_PLOGI_COMP: case RPSM_EVENT_LOGO_IMP: case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: + case RPSM_EVENT_SCN_OFFLINE: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); bfa_fcs_rport_fcs_offline_action(rport); break; @@ -561,9 +608,10 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_fcs_offline_action(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_LOGO_IMP: case RPSM_EVENT_ADDRESS_CHANGE: + case RPSM_EVENT_SCN_OFFLINE: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); bfa_fcs_rport_fcs_offline_action(rport); break; @@ -595,14 +643,15 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_trc(rport->fcs, event); switch (event) { - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery_sending); rport->ns_retries = 0; bfa_fcs_rport_send_nsdisc(rport, NULL); } else { - bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); + bfa_sm_set_state(rport, + bfa_fcs_rport_sm_adisc_online_sending); bfa_fcs_rport_send_adisc(rport, NULL); } break; @@ -610,6 +659,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) case RPSM_EVENT_PLOGI_RCVD: case RPSM_EVENT_LOGO_IMP: case RPSM_EVENT_ADDRESS_CHANGE: + case RPSM_EVENT_SCN_OFFLINE: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); bfa_fcs_rport_hal_offline_action(rport); break; @@ -625,6 +675,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_fcs_rport_hal_offline_action(rport); break; + case RPSM_EVENT_SCN_ONLINE: case RPSM_EVENT_PLOGI_COMP: break; @@ -656,7 +707,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_hal_offline_action(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: /* * ignore SCN, wait for response to query itself */ @@ -696,7 +747,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) switch (event) { case RPSM_EVENT_ACCEPTED: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); + bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_online_sending); bfa_fcs_rport_send_adisc(rport, NULL); break; @@ -718,7 +769,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_fcs_rport_hal_offline_action(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: break; case RPSM_EVENT_LOGO_RCVD: @@ -747,7 +798,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) * authenticating with rport. FC-4s are paused. */ static void -bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, +bfa_fcs_rport_sm_adisc_online_sending(struct bfa_fcs_rport_s *rport, enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); @@ -756,7 +807,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc); + bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_online); break; case RPSM_EVENT_DELETE: @@ -779,7 +830,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_hal_offline_action(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: break; case RPSM_EVENT_PLOGI_RCVD: @@ -798,7 +849,8 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, * FC-4s are paused. */ static void -bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) +bfa_fcs_rport_sm_adisc_online(struct bfa_fcs_rport_s *rport, + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -831,7 +883,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_fcs_rport_hal_offline_action(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: /* * already processing RSCN */ @@ -856,7 +908,96 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) } /* - * Rport has sent LOGO. Awaiting FC-4 offline completion callback. + * ADISC is being sent for authenticating with rport + * Already did offline actions. + */ +static void +bfa_fcs_rport_sm_adisc_offline_sending(struct bfa_fcs_rport_s *rport, + enum rport_event event) +{ + bfa_trc(rport->fcs, rport->pwwn); + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPSM_EVENT_FCXP_SENT: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_offline); + break; + + case RPSM_EVENT_DELETE: + case RPSM_EVENT_SCN_OFFLINE: + case RPSM_EVENT_LOGO_IMP: + case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_fcxp_walloc_cancel(rport->fcs->bfa, + &rport->fcxp_wqe); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; + + case RPSM_EVENT_PLOGI_RCVD: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); + bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); + bfa_fcs_rport_send_plogiacc(rport, NULL); + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +/* + * ADISC to rport + * Already did offline actions + */ +static void +bfa_fcs_rport_sm_adisc_offline(struct bfa_fcs_rport_s *rport, + enum rport_event event) +{ + bfa_trc(rport->fcs, rport->pwwn); + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPSM_EVENT_ACCEPTED: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); + bfa_fcs_rport_hal_online(rport); + break; + + case RPSM_EVENT_PLOGI_RCVD: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); + bfa_fcxp_discard(rport->fcxp); + bfa_fcs_rport_send_plogiacc(rport, NULL); + break; + + case RPSM_EVENT_FAILED: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; + + case RPSM_EVENT_DELETE: + case RPSM_EVENT_SCN_OFFLINE: + case RPSM_EVENT_LOGO_IMP: + case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_fcxp_discard(rport->fcxp); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +/* + * Rport has sent LOGO. Awaiting FC-4 offline completion callback. */ static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, @@ -881,6 +1022,8 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_off_delete); break; + case RPSM_EVENT_SCN_ONLINE: + case RPSM_EVENT_SCN_OFFLINE: case RPSM_EVENT_HCB_ONLINE: case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: @@ -945,6 +1088,8 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_hal_offline(rport); break; + case RPSM_EVENT_SCN_ONLINE: + break; case RPSM_EVENT_LOGO_RCVD: /* * Rport is going offline. Just ack the logo @@ -956,8 +1101,9 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_prlo_acc(rport); break; + case RPSM_EVENT_SCN_OFFLINE: case RPSM_EVENT_HCB_ONLINE: - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_LOGO_IMP: case RPSM_EVENT_ADDRESS_CHANGE: /* @@ -1015,6 +1161,19 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; bfa_fcs_rport_send_nsdisc(rport, NULL); + } else if (bfa_fcport_get_topology(rport->port->fcs->bfa) == + BFA_PORT_TOPOLOGY_LOOP) { + if (rport->scn_online) { + bfa_sm_set_state(rport, + bfa_fcs_rport_sm_adisc_offline_sending); + bfa_fcs_rport_send_adisc(rport, NULL); + } else { + bfa_sm_set_state(rport, + bfa_fcs_rport_sm_offline); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + } } else { bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); rport->plogi_retries = 0; @@ -1027,7 +1186,9 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_free(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_SCN_ONLINE: + case RPSM_EVENT_SCN_OFFLINE: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_PLOGI_RCVD: @@ -1106,6 +1267,8 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); break; + case RPSM_EVENT_SCN_ONLINE: + case RPSM_EVENT_SCN_OFFLINE: case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: /* @@ -1146,6 +1309,8 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, bfa_sm_set_state(rport, bfa_fcs_rport_sm_delete_pending); break; + case RPSM_EVENT_SCN_ONLINE: + case RPSM_EVENT_SCN_OFFLINE: case RPSM_EVENT_ADDRESS_CHANGE: break; @@ -1172,7 +1337,9 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_free(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_SCN_ONLINE: + case RPSM_EVENT_SCN_OFFLINE: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_ADDRESS_CHANGE: break; @@ -1209,10 +1376,12 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_fcs_rport_free(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); bfa_timer_stop(&rport->timer); + WARN_ON(!(bfa_fcport_get_topology(rport->port->fcs->bfa) != + BFA_PORT_TOPOLOGY_LOOP)); + bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; bfa_fcs_rport_send_nsdisc(rport, NULL); break; @@ -1232,6 +1401,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_LOGO_IMP: + case RPSM_EVENT_SCN_OFFLINE: break; case RPSM_EVENT_PLOGI_COMP: @@ -1240,6 +1410,12 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_fcs_rport_fcs_online_action(rport); break; + case RPSM_EVENT_SCN_ONLINE: + bfa_timer_stop(&rport->timer); + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); + bfa_fcs_rport_send_plogi(rport, NULL); + break; + case RPSM_EVENT_PLOGI_SEND: bfa_timer_stop(&rport->timer); bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); @@ -1280,7 +1456,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_plogiacc(rport, NULL); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_PLOGI_SEND: @@ -1326,7 +1502,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_nsdisc(rport, NULL); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: case RPSM_EVENT_ADDRESS_CHANGE: bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); bfa_timer_stop(&rport->timer); @@ -1439,7 +1615,7 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_PRLO_RCVD: bfa_fcs_rport_send_prlo_acc(rport); break; - case RPSM_EVENT_SCN: + case RPSM_EVENT_FAB_SCN: /* * ignore, wait for NS query response */ @@ -2546,7 +2722,7 @@ void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport) { rport->stats.rscns++; - bfa_sm_send_event(rport, RPSM_EVENT_SCN); + bfa_sm_send_event(rport, RPSM_EVENT_FAB_SCN); } /* @@ -2621,6 +2797,48 @@ bfa_cb_rport_qos_scn_flowid(void *cbarg, bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data); } +void +bfa_cb_rport_scn_online(struct bfa_s *bfa) +{ + struct bfa_fcs_s *fcs = &((struct bfad_s *)bfa->bfad)->bfa_fcs; + struct bfa_fcs_lport_s *port = bfa_fcs_get_base_port(fcs); + struct bfa_fcs_rport_s *rp; + struct list_head *qe; + + list_for_each(qe, &port->rport_q) { + rp = (struct bfa_fcs_rport_s *) qe; + bfa_sm_send_event(rp, RPSM_EVENT_SCN_ONLINE); + rp->scn_online = BFA_TRUE; + } + + if (bfa_fcs_lport_is_online(port)) + bfa_fcs_lport_lip_scn_online(port); +} + +void +bfa_cb_rport_scn_no_dev(void *rport) +{ + struct bfa_fcs_rport_s *rp = rport; + + bfa_sm_send_event(rp, RPSM_EVENT_SCN_OFFLINE); + rp->scn_online = BFA_FALSE; +} + +void +bfa_cb_rport_scn_offline(struct bfa_s *bfa) +{ + struct bfa_fcs_s *fcs = &((struct bfad_s *)bfa->bfad)->bfa_fcs; + struct bfa_fcs_lport_s *port = bfa_fcs_get_base_port(fcs); + struct bfa_fcs_rport_s *rp; + struct list_head *qe; + + list_for_each(qe, &port->rport_q) { + rp = (struct bfa_fcs_rport_s *) qe; + bfa_sm_send_event(rp, RPSM_EVENT_SCN_OFFLINE); + rp->scn_online = BFA_FALSE; + } +} + /* * brief * This routine is a static BFA callback when there is a QoS priority @@ -2808,6 +3026,9 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, struct bfa_rport_qos_attr_s qos_attr; struct bfa_fcs_lport_s *port = rport->port; bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed; + struct bfa_port_attr_s port_attr; + + bfa_fcport_get_attr(rport->fcs->bfa, &port_attr); memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); memset(&qos_attr, 0, sizeof(struct bfa_rport_qos_attr_s)); @@ -2838,7 +3059,8 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, rport_speed = bfa_fcport_get_ratelim_speed(rport->fcs->bfa); - if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port)) + if ((bfa_fcs_lport_get_rport_max_speed(port) != + BFA_PORT_SPEED_UNKNOWN) && (rport_speed < port_attr.speed)) rport_attr->trl_enforced = BFA_TRUE; } } diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 75ca8752b9f4..0116c1032e25 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -731,8 +731,7 @@ bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf) /* * Unlock the hw semaphore. Should be here only once per boot. */ - readl(iocpf->ioc->ioc_regs.ioc_sem_reg); - writel(1, iocpf->ioc->ioc_regs.ioc_sem_reg); + bfa_ioc_ownership_reset(iocpf->ioc); /* * unlock init semaphore. @@ -1751,6 +1750,7 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) attr->card_type = be32_to_cpu(attr->card_type); attr->maxfrsize = be16_to_cpu(attr->maxfrsize); ioc->fcmode = (attr->port_mode == BFI_PORT_MODE_FC); + attr->mfg_year = be16_to_cpu(attr->mfg_year); bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); } @@ -2497,6 +2497,9 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, ad_attr->cna_capable = bfa_ioc_is_cna(ioc); ad_attr->trunk_capable = (ad_attr->nports > 1) && !bfa_ioc_is_cna(ioc) && !ad_attr->is_mezz; + ad_attr->mfg_day = ioc_attr->mfg_day; + ad_attr->mfg_month = ioc_attr->mfg_month; + ad_attr->mfg_year = ioc_attr->mfg_year; } enum bfa_ioc_type_e @@ -2923,7 +2926,7 @@ bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc) return; } - if (ioc->iocpf.poll_time >= BFA_IOC_TOV) + if (ioc->iocpf.poll_time >= (3 * BFA_IOC_TOV)) bfa_iocpf_timeout(ioc); else { ioc->iocpf.poll_time += BFA_IOC_POLL_TOV; @@ -3016,7 +3019,6 @@ bfa_ablk_config_swap(struct bfa_ablk_cfg_s *cfg) struct bfa_ablk_cfg_inst_s *cfg_inst; int i, j; u16 be16; - u32 be32; for (i = 0; i < BFA_ABLK_MAX; i++) { cfg_inst = &cfg->inst[i]; @@ -3027,8 +3029,10 @@ bfa_ablk_config_swap(struct bfa_ablk_cfg_s *cfg) cfg_inst->pf_cfg[j].num_qpairs = be16_to_cpu(be16); be16 = cfg_inst->pf_cfg[j].num_vectors; cfg_inst->pf_cfg[j].num_vectors = be16_to_cpu(be16); - be32 = cfg_inst->pf_cfg[j].bw; - cfg_inst->pf_cfg[j].bw = be16_to_cpu(be32); + be16 = cfg_inst->pf_cfg[j].bw_min; + cfg_inst->pf_cfg[j].bw_min = be16_to_cpu(be16); + be16 = cfg_inst->pf_cfg[j].bw_max; + cfg_inst->pf_cfg[j].bw_max = be16_to_cpu(be16); } } } @@ -3170,7 +3174,8 @@ bfa_ablk_query(struct bfa_ablk_s *ablk, struct bfa_ablk_cfg_s *ablk_cfg, bfa_status_t bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, + u8 port, enum bfi_pcifn_class personality, + u16 bw_min, u16 bw_max, bfa_ablk_cbfn_t cbfn, void *cbarg) { struct bfi_ablk_h2i_pf_req_s *m; @@ -3194,7 +3199,8 @@ bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_CREATE, bfa_ioc_portid(ablk->ioc)); m->pers = cpu_to_be16((u16)personality); - m->bw = cpu_to_be32(bw); + m->bw_min = cpu_to_be16(bw_min); + m->bw_max = cpu_to_be16(bw_max); m->port = port; bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); @@ -3294,8 +3300,8 @@ bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, enum bfa_mode_s mode, } bfa_status_t -bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) +bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, u16 bw_min, + u16 bw_max, bfa_ablk_cbfn_t cbfn, void *cbarg) { struct bfi_ablk_h2i_pf_req_s *m; @@ -3317,7 +3323,8 @@ bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_UPDATE, bfa_ioc_portid(ablk->ioc)); m->pcifn = (u8)pcifn; - m->bw = cpu_to_be32(bw); + m->bw_min = cpu_to_be16(bw_min); + m->bw_max = cpu_to_be16(bw_max); bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); return BFA_STATUS_OK; @@ -4680,22 +4687,25 @@ diag_tempsensor_comp(struct bfa_diag_s *diag, bfi_diag_ts_rsp_t *rsp) diag->tsensor.temp->temp = be16_to_cpu(rsp->temp); diag->tsensor.temp->ts_junc = rsp->ts_junc; diag->tsensor.temp->ts_brd = rsp->ts_brd; - diag->tsensor.temp->status = BFA_STATUS_OK; if (rsp->ts_brd) { + /* tsensor.temp->status is brd_temp status */ + diag->tsensor.temp->status = rsp->status; if (rsp->status == BFA_STATUS_OK) { diag->tsensor.temp->brd_temp = be16_to_cpu(rsp->brd_temp); - } else { - bfa_trc(diag, rsp->status); + } else diag->tsensor.temp->brd_temp = 0; - diag->tsensor.temp->status = BFA_STATUS_DEVBUSY; - } } + + bfa_trc(diag, rsp->status); bfa_trc(diag, rsp->ts_junc); bfa_trc(diag, rsp->temp); bfa_trc(diag, rsp->ts_brd); bfa_trc(diag, rsp->brd_temp); + + /* tsensor status is always good bcos we always have junction temp */ + diag->tsensor.status = BFA_STATUS_OK; diag->tsensor.cbfn(diag->tsensor.cbarg, diag->tsensor.status); diag->tsensor.lock = 0; } @@ -4924,6 +4934,7 @@ bfa_diag_tsensor_query(struct bfa_diag_s *diag, diag->tsensor.temp = result; diag->tsensor.cbfn = cbfn; diag->tsensor.cbarg = cbarg; + diag->tsensor.status = BFA_STATUS_OK; /* Send msg to fw */ diag_tempsensor_send(diag); @@ -5615,7 +5626,7 @@ bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) } bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read); bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); + bfa_dconf_timer, dconf, 2 * BFA_DCONF_UPDATE_TOV); bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa), BFA_FLASH_PART_DRV, dconf->instance, dconf->dconf, @@ -5655,7 +5666,7 @@ bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf, break; case BFA_DCONF_SM_TIMEOUT: bfa_sm_set_state(dconf, bfa_dconf_sm_ready); - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_IOC_FAILED); + bfa_ioc_suspend(&dconf->bfa->ioc); break; case BFA_DCONF_SM_EXIT: bfa_timer_stop(&dconf->timer); @@ -5853,7 +5864,6 @@ bfa_dconf_init_cb(void *arg, bfa_status_t status) struct bfa_s *bfa = arg; struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP); if (status == BFA_STATUS_OK) { bfa_dconf_read_data_valid(bfa) = BFA_TRUE; if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE) @@ -5861,6 +5871,7 @@ bfa_dconf_init_cb(void *arg, bfa_status_t status) if (dconf->dconf->hdr.version != BFI_DCONF_VERSION) dconf->dconf->hdr.version = BFI_DCONF_VERSION; } + bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP); bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_DCONF_DONE); } @@ -5945,3 +5956,448 @@ bfa_dconf_modexit(struct bfa_s *bfa) struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT); } + +/* + * FRU specific functions + */ + +#define BFA_FRU_DMA_BUF_SZ 0x02000 /* 8k dma buffer */ +#define BFA_FRU_CHINOOK_MAX_SIZE 0x10000 +#define BFA_FRU_LIGHTNING_MAX_SIZE 0x200 + +static void +bfa_fru_notify(void *cbarg, enum bfa_ioc_event_e event) +{ + struct bfa_fru_s *fru = cbarg; + + bfa_trc(fru, event); + + switch (event) { + case BFA_IOC_E_DISABLED: + case BFA_IOC_E_FAILED: + if (fru->op_busy) { + fru->status = BFA_STATUS_IOC_FAILURE; + fru->cbfn(fru->cbarg, fru->status); + fru->op_busy = 0; + } + break; + + default: + break; + } +} + +/* + * Send fru write request. + * + * @param[in] cbarg - callback argument + */ +static void +bfa_fru_write_send(void *cbarg, enum bfi_fru_h2i_msgs msg_type) +{ + struct bfa_fru_s *fru = cbarg; + struct bfi_fru_write_req_s *msg = + (struct bfi_fru_write_req_s *) fru->mb.msg; + u32 len; + + msg->offset = cpu_to_be32(fru->addr_off + fru->offset); + len = (fru->residue < BFA_FRU_DMA_BUF_SZ) ? + fru->residue : BFA_FRU_DMA_BUF_SZ; + msg->length = cpu_to_be32(len); + + /* + * indicate if it's the last msg of the whole write operation + */ + msg->last = (len == fru->residue) ? 1 : 0; + + bfi_h2i_set(msg->mh, BFI_MC_FRU, msg_type, bfa_ioc_portid(fru->ioc)); + bfa_alen_set(&msg->alen, len, fru->dbuf_pa); + + memcpy(fru->dbuf_kva, fru->ubuf + fru->offset, len); + bfa_ioc_mbox_queue(fru->ioc, &fru->mb); + + fru->residue -= len; + fru->offset += len; +} + +/* + * Send fru read request. + * + * @param[in] cbarg - callback argument + */ +static void +bfa_fru_read_send(void *cbarg, enum bfi_fru_h2i_msgs msg_type) +{ + struct bfa_fru_s *fru = cbarg; + struct bfi_fru_read_req_s *msg = + (struct bfi_fru_read_req_s *) fru->mb.msg; + u32 len; + + msg->offset = cpu_to_be32(fru->addr_off + fru->offset); + len = (fru->residue < BFA_FRU_DMA_BUF_SZ) ? + fru->residue : BFA_FRU_DMA_BUF_SZ; + msg->length = cpu_to_be32(len); + bfi_h2i_set(msg->mh, BFI_MC_FRU, msg_type, bfa_ioc_portid(fru->ioc)); + bfa_alen_set(&msg->alen, len, fru->dbuf_pa); + bfa_ioc_mbox_queue(fru->ioc, &fru->mb); +} + +/* + * Flash memory info API. + * + * @param[in] mincfg - minimal cfg variable + */ +u32 +bfa_fru_meminfo(bfa_boolean_t mincfg) +{ + /* min driver doesn't need fru */ + if (mincfg) + return 0; + + return BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); +} + +/* + * Flash attach API. + * + * @param[in] fru - fru structure + * @param[in] ioc - ioc structure + * @param[in] dev - device structure + * @param[in] trcmod - trace module + * @param[in] logmod - log module + */ +void +bfa_fru_attach(struct bfa_fru_s *fru, struct bfa_ioc_s *ioc, void *dev, + struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) +{ + fru->ioc = ioc; + fru->trcmod = trcmod; + fru->cbfn = NULL; + fru->cbarg = NULL; + fru->op_busy = 0; + + bfa_ioc_mbox_regisr(fru->ioc, BFI_MC_FRU, bfa_fru_intr, fru); + bfa_q_qe_init(&fru->ioc_notify); + bfa_ioc_notify_init(&fru->ioc_notify, bfa_fru_notify, fru); + list_add_tail(&fru->ioc_notify.qe, &fru->ioc->notify_q); + + /* min driver doesn't need fru */ + if (mincfg) { + fru->dbuf_kva = NULL; + fru->dbuf_pa = 0; + } +} + +/* + * Claim memory for fru + * + * @param[in] fru - fru structure + * @param[in] dm_kva - pointer to virtual memory address + * @param[in] dm_pa - frusical memory address + * @param[in] mincfg - minimal cfg variable + */ +void +bfa_fru_memclaim(struct bfa_fru_s *fru, u8 *dm_kva, u64 dm_pa, + bfa_boolean_t mincfg) +{ + if (mincfg) + return; + + fru->dbuf_kva = dm_kva; + fru->dbuf_pa = dm_pa; + memset(fru->dbuf_kva, 0, BFA_FRU_DMA_BUF_SZ); + dm_kva += BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); + dm_pa += BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); +} + +/* + * Update fru vpd image. + * + * @param[in] fru - fru structure + * @param[in] buf - update data buffer + * @param[in] len - data buffer length + * @param[in] offset - offset relative to starting address + * @param[in] cbfn - callback function + * @param[in] cbarg - callback argument + * + * Return status. + */ +bfa_status_t +bfa_fruvpd_update(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg) +{ + bfa_trc(fru, BFI_FRUVPD_H2I_WRITE_REQ); + bfa_trc(fru, len); + bfa_trc(fru, offset); + + if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) + return BFA_STATUS_FRU_NOT_PRESENT; + + if (fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK) + return BFA_STATUS_CMD_NOTSUPP; + + if (!bfa_ioc_is_operational(fru->ioc)) + return BFA_STATUS_IOC_NON_OP; + + if (fru->op_busy) { + bfa_trc(fru, fru->op_busy); + return BFA_STATUS_DEVBUSY; + } + + fru->op_busy = 1; + + fru->cbfn = cbfn; + fru->cbarg = cbarg; + fru->residue = len; + fru->offset = 0; + fru->addr_off = offset; + fru->ubuf = buf; + + bfa_fru_write_send(fru, BFI_FRUVPD_H2I_WRITE_REQ); + + return BFA_STATUS_OK; +} + +/* + * Read fru vpd image. + * + * @param[in] fru - fru structure + * @param[in] buf - read data buffer + * @param[in] len - data buffer length + * @param[in] offset - offset relative to starting address + * @param[in] cbfn - callback function + * @param[in] cbarg - callback argument + * + * Return status. + */ +bfa_status_t +bfa_fruvpd_read(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg) +{ + bfa_trc(fru, BFI_FRUVPD_H2I_READ_REQ); + bfa_trc(fru, len); + bfa_trc(fru, offset); + + if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) + return BFA_STATUS_FRU_NOT_PRESENT; + + if (fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK) + return BFA_STATUS_CMD_NOTSUPP; + + if (!bfa_ioc_is_operational(fru->ioc)) + return BFA_STATUS_IOC_NON_OP; + + if (fru->op_busy) { + bfa_trc(fru, fru->op_busy); + return BFA_STATUS_DEVBUSY; + } + + fru->op_busy = 1; + + fru->cbfn = cbfn; + fru->cbarg = cbarg; + fru->residue = len; + fru->offset = 0; + fru->addr_off = offset; + fru->ubuf = buf; + bfa_fru_read_send(fru, BFI_FRUVPD_H2I_READ_REQ); + + return BFA_STATUS_OK; +} + +/* + * Get maximum size fru vpd image. + * + * @param[in] fru - fru structure + * @param[out] size - maximum size of fru vpd data + * + * Return status. + */ +bfa_status_t +bfa_fruvpd_get_max_size(struct bfa_fru_s *fru, u32 *max_size) +{ + if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) + return BFA_STATUS_FRU_NOT_PRESENT; + + if (!bfa_ioc_is_operational(fru->ioc)) + return BFA_STATUS_IOC_NON_OP; + + if (fru->ioc->attr->card_type == BFA_MFG_TYPE_CHINOOK) + *max_size = BFA_FRU_CHINOOK_MAX_SIZE; + else + return BFA_STATUS_CMD_NOTSUPP; + return BFA_STATUS_OK; +} +/* + * tfru write. + * + * @param[in] fru - fru structure + * @param[in] buf - update data buffer + * @param[in] len - data buffer length + * @param[in] offset - offset relative to starting address + * @param[in] cbfn - callback function + * @param[in] cbarg - callback argument + * + * Return status. + */ +bfa_status_t +bfa_tfru_write(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg) +{ + bfa_trc(fru, BFI_TFRU_H2I_WRITE_REQ); + bfa_trc(fru, len); + bfa_trc(fru, offset); + bfa_trc(fru, *((u8 *) buf)); + + if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) + return BFA_STATUS_FRU_NOT_PRESENT; + + if (!bfa_ioc_is_operational(fru->ioc)) + return BFA_STATUS_IOC_NON_OP; + + if (fru->op_busy) { + bfa_trc(fru, fru->op_busy); + return BFA_STATUS_DEVBUSY; + } + + fru->op_busy = 1; + + fru->cbfn = cbfn; + fru->cbarg = cbarg; + fru->residue = len; + fru->offset = 0; + fru->addr_off = offset; + fru->ubuf = buf; + + bfa_fru_write_send(fru, BFI_TFRU_H2I_WRITE_REQ); + + return BFA_STATUS_OK; +} + +/* + * tfru read. + * + * @param[in] fru - fru structure + * @param[in] buf - read data buffer + * @param[in] len - data buffer length + * @param[in] offset - offset relative to starting address + * @param[in] cbfn - callback function + * @param[in] cbarg - callback argument + * + * Return status. + */ +bfa_status_t +bfa_tfru_read(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg) +{ + bfa_trc(fru, BFI_TFRU_H2I_READ_REQ); + bfa_trc(fru, len); + bfa_trc(fru, offset); + + if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) + return BFA_STATUS_FRU_NOT_PRESENT; + + if (!bfa_ioc_is_operational(fru->ioc)) + return BFA_STATUS_IOC_NON_OP; + + if (fru->op_busy) { + bfa_trc(fru, fru->op_busy); + return BFA_STATUS_DEVBUSY; + } + + fru->op_busy = 1; + + fru->cbfn = cbfn; + fru->cbarg = cbarg; + fru->residue = len; + fru->offset = 0; + fru->addr_off = offset; + fru->ubuf = buf; + bfa_fru_read_send(fru, BFI_TFRU_H2I_READ_REQ); + + return BFA_STATUS_OK; +} + +/* + * Process fru response messages upon receiving interrupts. + * + * @param[in] fruarg - fru structure + * @param[in] msg - message structure + */ +void +bfa_fru_intr(void *fruarg, struct bfi_mbmsg_s *msg) +{ + struct bfa_fru_s *fru = fruarg; + struct bfi_fru_rsp_s *rsp = (struct bfi_fru_rsp_s *)msg; + u32 status; + + bfa_trc(fru, msg->mh.msg_id); + + if (!fru->op_busy) { + /* + * receiving response after ioc failure + */ + bfa_trc(fru, 0x9999); + return; + } + + switch (msg->mh.msg_id) { + case BFI_FRUVPD_I2H_WRITE_RSP: + case BFI_TFRU_I2H_WRITE_RSP: + status = be32_to_cpu(rsp->status); + bfa_trc(fru, status); + + if (status != BFA_STATUS_OK || fru->residue == 0) { + fru->status = status; + fru->op_busy = 0; + if (fru->cbfn) + fru->cbfn(fru->cbarg, fru->status); + } else { + bfa_trc(fru, fru->offset); + if (msg->mh.msg_id == BFI_FRUVPD_I2H_WRITE_RSP) + bfa_fru_write_send(fru, + BFI_FRUVPD_H2I_WRITE_REQ); + else + bfa_fru_write_send(fru, + BFI_TFRU_H2I_WRITE_REQ); + } + break; + case BFI_FRUVPD_I2H_READ_RSP: + case BFI_TFRU_I2H_READ_RSP: + status = be32_to_cpu(rsp->status); + bfa_trc(fru, status); + + if (status != BFA_STATUS_OK) { + fru->status = status; + fru->op_busy = 0; + if (fru->cbfn) + fru->cbfn(fru->cbarg, fru->status); + } else { + u32 len = be32_to_cpu(rsp->length); + + bfa_trc(fru, fru->offset); + bfa_trc(fru, len); + + memcpy(fru->ubuf + fru->offset, fru->dbuf_kva, len); + fru->residue -= len; + fru->offset += len; + + if (fru->residue == 0) { + fru->status = status; + fru->op_busy = 0; + if (fru->cbfn) + fru->cbfn(fru->cbarg, fru->status); + } else { + if (msg->mh.msg_id == BFI_FRUVPD_I2H_READ_RSP) + bfa_fru_read_send(fru, + BFI_FRUVPD_H2I_READ_REQ); + else + bfa_fru_read_send(fru, + BFI_TFRU_H2I_READ_REQ); + } + } + break; + default: + WARN_ON(1); + } +} diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index b2856f96567c..23a90e7b7107 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -702,6 +702,55 @@ void bfa_phy_memclaim(struct bfa_phy_s *phy, void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg); /* + * FRU module specific + */ +typedef void (*bfa_cb_fru_t) (void *cbarg, bfa_status_t status); + +struct bfa_fru_s { + struct bfa_ioc_s *ioc; /* back pointer to ioc */ + struct bfa_trc_mod_s *trcmod; /* trace module */ + u8 op_busy; /* operation busy flag */ + u8 rsv[3]; + u32 residue; /* residual length */ + u32 offset; /* offset */ + bfa_status_t status; /* status */ + u8 *dbuf_kva; /* dma buf virtual address */ + u64 dbuf_pa; /* dma buf physical address */ + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ + bfa_cb_fru_t cbfn; /* user callback function */ + void *cbarg; /* user callback arg */ + u8 *ubuf; /* user supplied buffer */ + struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ + u32 addr_off; /* fru address offset */ + struct bfa_mbox_cmd_s mb; /* mailbox */ + struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ + struct bfa_mem_dma_s fru_dma; +}; + +#define BFA_FRU(__bfa) (&(__bfa)->modules.fru) +#define BFA_MEM_FRU_DMA(__bfa) (&(BFA_FRU(__bfa)->fru_dma)) + +bfa_status_t bfa_fruvpd_update(struct bfa_fru_s *fru, + void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg); +bfa_status_t bfa_fruvpd_read(struct bfa_fru_s *fru, + void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg); +bfa_status_t bfa_fruvpd_get_max_size(struct bfa_fru_s *fru, u32 *max_size); +bfa_status_t bfa_tfru_write(struct bfa_fru_s *fru, + void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg); +bfa_status_t bfa_tfru_read(struct bfa_fru_s *fru, + void *buf, u32 len, u32 offset, + bfa_cb_fru_t cbfn, void *cbarg); +u32 bfa_fru_meminfo(bfa_boolean_t mincfg); +void bfa_fru_attach(struct bfa_fru_s *fru, struct bfa_ioc_s *ioc, + void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); +void bfa_fru_memclaim(struct bfa_fru_s *fru, + u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); +void bfa_fru_intr(void *fruarg, struct bfi_mbmsg_s *msg); + +/* * Driver Config( dconf) specific */ #define BFI_DCONF_SIGNATURE 0xabcdabcd @@ -716,6 +765,7 @@ struct bfa_dconf_hdr_s { struct bfa_dconf_s { struct bfa_dconf_hdr_s hdr; struct bfa_lunmask_cfg_s lun_mask; + struct bfa_throttle_cfg_s throttle_cfg; }; #pragma pack() @@ -738,6 +788,8 @@ struct bfa_dconf_mod_s { #define bfa_dconf_read_data_valid(__bfa) \ (BFA_DCONF_MOD(__bfa)->read_data_valid) #define BFA_DCONF_UPDATE_TOV 5000 /* memtest timeout in msec */ +#define bfa_dconf_get_min_cfg(__bfa) \ + (BFA_DCONF_MOD(__bfa)->min_cfg) void bfa_dconf_modinit(struct bfa_s *bfa); void bfa_dconf_modexit(struct bfa_s *bfa); @@ -761,7 +813,8 @@ bfa_status_t bfa_dconf_update(struct bfa_s *bfa); #define bfa_ioc_maxfrsize(__ioc) ((__ioc)->attr->maxfrsize) #define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit) #define bfa_ioc_speed_sup(__ioc) \ - BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop) + ((bfa_ioc_is_cna(__ioc)) ? BFA_PORT_SPEED_10GBPS : \ + BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)) #define bfa_ioc_get_nports(__ioc) \ BFI_ADAPTER_GETP(NPORTS, (__ioc)->attr->adapter_prop) @@ -885,12 +938,12 @@ bfa_status_t bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, enum bfa_mode_s mode, int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg); bfa_status_t bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); + u8 port, enum bfi_pcifn_class personality, + u16 bw_min, u16 bw_max, bfa_ablk_cbfn_t cbfn, void *cbarg); bfa_status_t bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); +bfa_status_t bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, + u16 bw_min, u16 bw_max, bfa_ablk_cbfn_t cbfn, void *cbarg); bfa_status_t bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg); bfa_status_t bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 2eb0c6a2938d..de4e726a1263 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c @@ -57,13 +57,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) u32 usecnt; struct bfi_ioc_image_hdr_s fwhdr; - /* - * If bios boot (flash based) -- do not increment usage count - */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < - BFA_IOC_FWIMG_MINSZ) - return BFA_TRUE; - bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); usecnt = readl(ioc->ioc_regs.ioc_usage_reg); @@ -115,13 +108,6 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) u32 usecnt; /* - * If bios boot (flash based) -- do not decrement usage count - */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < - BFA_IOC_FWIMG_MINSZ) - return; - - /* * decrement usage count */ bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); @@ -400,13 +386,12 @@ static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) { - if (bfa_ioc_is_cna(ioc)) { - bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); - writel(0, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); - writel(1, ioc->ioc_regs.ioc_usage_sem_reg); - } + bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); + writel(0, ioc->ioc_regs.ioc_usage_reg); + readl(ioc->ioc_regs.ioc_usage_sem_reg); + writel(1, ioc->ioc_regs.ioc_usage_sem_reg); + writel(0, ioc->ioc_regs.ioc_fail_sync); /* * Read the hw sem reg to make sure that it is locked * before we clear it. If it is not locked, writing 1 @@ -759,25 +744,6 @@ bfa_ioc_ct2_mem_init(void __iomem *rb) void bfa_ioc_ct2_mac_reset(void __iomem *rb) { - u32 r32; - - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - /* put port0, port1 MAC & AHB in reset */ writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), rb + CT2_CSI_MAC_CONTROL_REG(0)); @@ -785,8 +751,21 @@ bfa_ioc_ct2_mac_reset(void __iomem *rb) rb + CT2_CSI_MAC_CONTROL_REG(1)); } +static void +bfa_ioc_ct2_enable_flash(void __iomem *rb) +{ + u32 r32; + + r32 = readl((rb + PSS_GPIO_OUT_REG)); + writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG)); + r32 = readl((rb + PSS_GPIO_OE_REG)); + writel(r32 | 1, (rb + PSS_GPIO_OE_REG)); +} + #define CT2_NFC_MAX_DELAY 1000 -#define CT2_NFC_VER_VALID 0x143 +#define CT2_NFC_PAUSE_MAX_DELAY 4000 +#define CT2_NFC_VER_VALID 0x147 +#define CT2_NFC_STATE_RUNNING 0x20000001 #define BFA_IOC_PLL_POLL 1000000 static bfa_boolean_t @@ -802,6 +781,20 @@ bfa_ioc_ct2_nfc_halted(void __iomem *rb) } static void +bfa_ioc_ct2_nfc_halt(void __iomem *rb) +{ + int i; + + writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_SET_REG); + for (i = 0; i < CT2_NFC_MAX_DELAY; i++) { + if (bfa_ioc_ct2_nfc_halted(rb)) + break; + udelay(1000); + } + WARN_ON(!bfa_ioc_ct2_nfc_halted(rb)); +} + +static void bfa_ioc_ct2_nfc_resume(void __iomem *rb) { u32 r32; @@ -817,105 +810,142 @@ bfa_ioc_ct2_nfc_resume(void __iomem *rb) WARN_ON(1); } -bfa_status_t -bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode) +static void +bfa_ioc_ct2_clk_reset(void __iomem *rb) { - u32 wgn, r32, nfc_ver, i; + u32 r32; - wgn = readl(rb + CT2_WGN_STATUS); - nfc_ver = readl(rb + CT2_RSC_GPR15_REG); + bfa_ioc_ct2_sclk_init(rb); + bfa_ioc_ct2_lclk_init(rb); - if ((wgn == (__A2T_AHB_LOAD | __WGN_READY)) && - (nfc_ver >= CT2_NFC_VER_VALID)) { - if (bfa_ioc_ct2_nfc_halted(rb)) - bfa_ioc_ct2_nfc_resume(rb); + /* + * release soft reset on s_clk & l_clk + */ + r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); + writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, + (rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(__RESET_AND_START_SCLK_LCLK_PLLS, - rb + CT2_CSI_FW_CTL_SET_REG); + r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); + writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, + (rb + CT2_APP_PLL_LCLK_CTL_REG)); - for (i = 0; i < BFA_IOC_PLL_POLL; i++) { - r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG); - if (r32 & __RESET_AND_START_SCLK_LCLK_PLLS) - break; - } +} - WARN_ON(!(r32 & __RESET_AND_START_SCLK_LCLK_PLLS)); +static void +bfa_ioc_ct2_nfc_clk_reset(void __iomem *rb) +{ + u32 r32, i; - for (i = 0; i < BFA_IOC_PLL_POLL; i++) { - r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG); - if (!(r32 & __RESET_AND_START_SCLK_LCLK_PLLS)) - break; - } + r32 = readl((rb + PSS_CTL_REG)); + r32 |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET); + writel(r32, (rb + PSS_CTL_REG)); + + writel(__RESET_AND_START_SCLK_LCLK_PLLS, rb + CT2_CSI_FW_CTL_SET_REG); - WARN_ON(r32 & __RESET_AND_START_SCLK_LCLK_PLLS); + for (i = 0; i < BFA_IOC_PLL_POLL; i++) { + r32 = readl(rb + CT2_NFC_FLASH_STS_REG); + + if ((r32 & __FLASH_PLL_INIT_AND_RESET_IN_PROGRESS)) + break; + } + WARN_ON(!(r32 & __FLASH_PLL_INIT_AND_RESET_IN_PROGRESS)); + + for (i = 0; i < BFA_IOC_PLL_POLL; i++) { + r32 = readl(rb + CT2_NFC_FLASH_STS_REG); + + if (!(r32 & __FLASH_PLL_INIT_AND_RESET_IN_PROGRESS)) + break; + } + WARN_ON((r32 & __FLASH_PLL_INIT_AND_RESET_IN_PROGRESS)); + + r32 = readl(rb + CT2_CSI_FW_CTL_REG); + WARN_ON((r32 & __RESET_AND_START_SCLK_LCLK_PLLS)); +} + +static void +bfa_ioc_ct2_wait_till_nfc_running(void __iomem *rb) +{ + u32 r32; + int i; + + if (bfa_ioc_ct2_nfc_halted(rb)) + bfa_ioc_ct2_nfc_resume(rb); + for (i = 0; i < CT2_NFC_PAUSE_MAX_DELAY; i++) { + r32 = readl(rb + CT2_NFC_STS_REG); + if (r32 == CT2_NFC_STATE_RUNNING) + return; udelay(1000); + } - r32 = readl(rb + CT2_CSI_FW_CTL_REG); - WARN_ON(r32 & __RESET_AND_START_SCLK_LCLK_PLLS); - } else { - writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_SET_REG); - for (i = 0; i < CT2_NFC_MAX_DELAY; i++) { - r32 = readl(rb + CT2_NFC_CSR_SET_REG); - if (r32 & __NFC_CONTROLLER_HALTED) - break; - udelay(1000); - } + r32 = readl(rb + CT2_NFC_STS_REG); + WARN_ON(!(r32 == CT2_NFC_STATE_RUNNING)); +} - bfa_ioc_ct2_mac_reset(rb); - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); +bfa_status_t +bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode) +{ + u32 wgn, r32, nfc_ver; - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); + wgn = readl(rb + CT2_WGN_STATUS); + if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) { /* - * release soft reset on s_clk & l_clk + * If flash is corrupted, enable flash explicitly */ - r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - } + bfa_ioc_ct2_clk_reset(rb); + bfa_ioc_ct2_enable_flash(rb); - /* - * Announce flash device presence, if flash was corrupted. - */ - if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) { - r32 = readl(rb + PSS_GPIO_OUT_REG); - writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG)); - r32 = readl(rb + PSS_GPIO_OE_REG); - writel(r32 | 1, (rb + PSS_GPIO_OE_REG)); + bfa_ioc_ct2_mac_reset(rb); + + bfa_ioc_ct2_clk_reset(rb); + bfa_ioc_ct2_enable_flash(rb); + + } else { + nfc_ver = readl(rb + CT2_RSC_GPR15_REG); + + if ((nfc_ver >= CT2_NFC_VER_VALID) && + (wgn == (__A2T_AHB_LOAD | __WGN_READY))) { + + bfa_ioc_ct2_wait_till_nfc_running(rb); + + bfa_ioc_ct2_nfc_clk_reset(rb); + } else { + bfa_ioc_ct2_nfc_halt(rb); + + bfa_ioc_ct2_clk_reset(rb); + bfa_ioc_ct2_mac_reset(rb); + bfa_ioc_ct2_clk_reset(rb); + + } } /* * Mask the interrupts and clear any - * pending interrupts. + * pending interrupts left by BIOS/EFI */ + writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK)); writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK)); /* For first time initialization, no need to clear interrupts */ r32 = readl(rb + HOST_SEM5_REG); if (r32 & 0x1) { - r32 = readl(rb + CT2_LPU0_HOSTFN_CMD_STAT); + r32 = readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); if (r32 == 1) { - writel(1, rb + CT2_LPU0_HOSTFN_CMD_STAT); + writel(1, (rb + CT2_LPU0_HOSTFN_CMD_STAT)); readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); } - r32 = readl(rb + CT2_LPU1_HOSTFN_CMD_STAT); + r32 = readl((rb + CT2_LPU1_HOSTFN_CMD_STAT)); if (r32 == 1) { - writel(1, rb + CT2_LPU1_HOSTFN_CMD_STAT); - readl(rb + CT2_LPU1_HOSTFN_CMD_STAT); + writel(1, (rb + CT2_LPU1_HOSTFN_CMD_STAT)); + readl((rb + CT2_LPU1_HOSTFN_CMD_STAT)); } } bfa_ioc_ct2_mem_init(rb); - writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC0_STATE_REG); - writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC1_STATE_REG); + writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC0_STATE_REG)); + writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG)); return BFA_STATUS_OK; } diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h index 189fff71e3c2..a14c784ff3fc 100644 --- a/drivers/scsi/bfa/bfa_modules.h +++ b/drivers/scsi/bfa/bfa_modules.h @@ -45,6 +45,7 @@ struct bfa_modules_s { struct bfa_diag_s diag_mod; /* diagnostics module */ struct bfa_phy_s phy; /* phy module */ struct bfa_dconf_mod_s dconf_mod; /* DCONF common module */ + struct bfa_fru_s fru; /* fru module */ }; /* diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c index 95e4ad8759ac..8ea7697deb9b 100644 --- a/drivers/scsi/bfa/bfa_port.c +++ b/drivers/scsi/bfa/bfa_port.c @@ -250,6 +250,12 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, return BFA_STATUS_IOC_FAILURE; } + /* if port is d-port enabled, return error */ + if (port->dport_enabled) { + bfa_trc(port, BFA_STATUS_DPORT_ERR); + return BFA_STATUS_DPORT_ERR; + } + if (port->endis_pending) { bfa_trc(port, BFA_STATUS_DEVBUSY); return BFA_STATUS_DEVBUSY; @@ -300,6 +306,12 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, return BFA_STATUS_IOC_FAILURE; } + /* if port is d-port enabled, return error */ + if (port->dport_enabled) { + bfa_trc(port, BFA_STATUS_DPORT_ERR); + return BFA_STATUS_DPORT_ERR; + } + if (port->endis_pending) { bfa_trc(port, BFA_STATUS_DEVBUSY); return BFA_STATUS_DEVBUSY; @@ -431,6 +443,10 @@ bfa_port_notify(void *arg, enum bfa_ioc_event_e event) port->endis_cbfn = NULL; port->endis_pending = BFA_FALSE; } + + /* clear D-port mode */ + if (port->dport_enabled) + bfa_port_set_dportenabled(port, BFA_FALSE); break; default: break; @@ -467,6 +483,7 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, port->stats_cbfn = NULL; port->endis_cbfn = NULL; port->pbc_disabled = BFA_FALSE; + port->dport_enabled = BFA_FALSE; bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); bfa_q_qe_init(&port->ioc_notify); @@ -483,6 +500,21 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, } /* + * bfa_port_set_dportenabled(); + * + * Port module- set pbc disabled flag + * + * @param[in] port - Pointer to the Port module data structure + * + * @return void + */ +void +bfa_port_set_dportenabled(struct bfa_port_s *port, bfa_boolean_t enabled) +{ + port->dport_enabled = enabled; +} + +/* * CEE module specific definitions */ diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h index 947f897328d6..2fcab6bc6280 100644 --- a/drivers/scsi/bfa/bfa_port.h +++ b/drivers/scsi/bfa/bfa_port.h @@ -45,6 +45,7 @@ struct bfa_port_s { bfa_status_t endis_status; struct bfa_ioc_notify_s ioc_notify; bfa_boolean_t pbc_disabled; + bfa_boolean_t dport_enabled; struct bfa_mem_dma_s port_dma; }; @@ -66,6 +67,8 @@ bfa_status_t bfa_port_disable(struct bfa_port_s *port, u32 bfa_port_meminfo(void); void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa); +void bfa_port_set_dportenabled(struct bfa_port_s *port, + bfa_boolean_t enabled); /* * CEE declaration diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index b2538d60db34..299c1c889b33 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -67,6 +67,9 @@ enum bfa_fcport_sm_event { BFA_FCPORT_SM_LINKDOWN = 7, /* firmware linkup down */ BFA_FCPORT_SM_QRESUME = 8, /* CQ space available */ BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */ + BFA_FCPORT_SM_DPORTENABLE = 10, /* enable dport */ + BFA_FCPORT_SM_DPORTDISABLE = 11,/* disable dport */ + BFA_FCPORT_SM_FAA_MISCONFIG = 12, /* FAA misconfiguratin */ }; /* @@ -197,6 +200,10 @@ static void bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, enum bfa_fcport_sm_event event); static void bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_dport(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_faa_misconfig(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); static void bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, enum bfa_fcport_ln_sm_event event); @@ -226,6 +233,8 @@ static struct bfa_sm_table_s hal_port_sm_table[] = { {BFA_SM(bfa_fcport_sm_stopped), BFA_PORT_ST_STOPPED}, {BFA_SM(bfa_fcport_sm_iocdown), BFA_PORT_ST_IOCDOWN}, {BFA_SM(bfa_fcport_sm_iocfail), BFA_PORT_ST_IOCDOWN}, + {BFA_SM(bfa_fcport_sm_dport), BFA_PORT_ST_DPORT}, + {BFA_SM(bfa_fcport_sm_faa_misconfig), BFA_PORT_ST_FAA_MISCONFIG}, }; @@ -1244,6 +1253,12 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) * Just ignore */ break; + case BFA_LPS_SM_SET_N2N_PID: + /* + * When topology is set to loop, bfa_lps_set_n2n_pid() sends + * this event. Ignore this event. + */ + break; default: bfa_sm_fault(lps->bfa, event); @@ -1261,6 +1276,7 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) switch (event) { case BFA_LPS_SM_FWRSP: + case BFA_LPS_SM_OFFLINE: if (lps->status == BFA_STATUS_OK) { bfa_sm_set_state(lps, bfa_lps_sm_online); if (lps->fdisc) @@ -1289,7 +1305,6 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) bfa_lps_login_comp(lps); break; - case BFA_LPS_SM_OFFLINE: case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); break; @@ -2169,6 +2184,12 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); break; + case BFA_FCPORT_SM_FAA_MISCONFIG: + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); + bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig); + break; + default: bfa_sm_fault(fcport->bfa, event); } @@ -2225,6 +2246,12 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); break; + case BFA_FCPORT_SM_FAA_MISCONFIG: + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); + bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig); + break; + default: bfa_sm_fault(fcport->bfa, event); } @@ -2250,11 +2277,11 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) { bfa_trc(fcport->bfa, - pevent->link_state.vc_fcf.fcf.fipenabled); + pevent->link_state.attr.vc_fcf.fcf.fipenabled); bfa_trc(fcport->bfa, - pevent->link_state.vc_fcf.fcf.fipfailed); + pevent->link_state.attr.vc_fcf.fcf.fipfailed); - if (pevent->link_state.vc_fcf.fcf.fipfailed) + if (pevent->link_state.attr.vc_fcf.fcf.fipfailed) bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_FIP_FCF_DISC, 0, "FIP FCF Discovery Failed"); @@ -2311,6 +2338,12 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); break; + case BFA_FCPORT_SM_FAA_MISCONFIG: + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); + bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig); + break; + default: bfa_sm_fault(fcport->bfa, event); } @@ -2404,6 +2437,12 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, } break; + case BFA_FCPORT_SM_FAA_MISCONFIG: + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); + bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig); + break; + default: bfa_sm_fault(fcport->bfa, event); } @@ -2449,6 +2488,12 @@ bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, bfa_reqq_wcancel(&fcport->reqq_wait); break; + case BFA_FCPORT_SM_FAA_MISCONFIG: + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); + bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig); + break; + default: bfa_sm_fault(fcport->bfa, event); } @@ -2600,6 +2645,10 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); break; + case BFA_FCPORT_SM_DPORTENABLE: + bfa_sm_set_state(fcport, bfa_fcport_sm_dport); + break; + default: bfa_sm_fault(fcport->bfa, event); } @@ -2680,6 +2729,81 @@ bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, } } +static void +bfa_fcport_sm_dport(struct bfa_fcport_s *fcport, enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_DPORTENABLE: + case BFA_FCPORT_SM_DISABLE: + case BFA_FCPORT_SM_ENABLE: + case BFA_FCPORT_SM_START: + /* + * Ignore event for a port that is dport + */ + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); + break; + + case BFA_FCPORT_SM_DPORTDISABLE: + bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_faa_misconfig(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_DPORTENABLE: + case BFA_FCPORT_SM_ENABLE: + case BFA_FCPORT_SM_START: + /* + * Ignore event for a port as there is FAA misconfig + */ + break; + + case BFA_FCPORT_SM_DISABLE: + if (bfa_fcport_send_disable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); + else + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait); + + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); + bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + /* * Link state is down */ @@ -2943,6 +3067,7 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, */ do_gettimeofday(&tv); fcport->stats_reset_time = tv.tv_sec; + fcport->stats_dma_ready = BFA_FALSE; /* * initialize and set default configuration @@ -2953,6 +3078,9 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, port_cfg->maxfrsize = 0; port_cfg->trl_def_speed = BFA_PORT_SPEED_1GBPS; + port_cfg->qos_bw.high = BFA_QOS_BW_HIGH; + port_cfg->qos_bw.med = BFA_QOS_BW_MED; + port_cfg->qos_bw.low = BFA_QOS_BW_LOW; INIT_LIST_HEAD(&fcport->stats_pending_q); INIT_LIST_HEAD(&fcport->statsclr_pending_q); @@ -2996,6 +3124,21 @@ bfa_fcport_iocdisable(struct bfa_s *bfa) bfa_trunk_iocdisable(bfa); } +/* + * Update loop info in fcport for SCN online + */ +static void +bfa_fcport_update_loop_info(struct bfa_fcport_s *fcport, + struct bfa_fcport_loop_info_s *loop_info) +{ + fcport->myalpa = loop_info->myalpa; + fcport->alpabm_valid = + loop_info->alpabm_val; + memcpy(fcport->alpabm.alpa_bm, + loop_info->alpabm.alpa_bm, + sizeof(struct fc_alpabm_s)); +} + static void bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) { @@ -3005,12 +3148,15 @@ bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) fcport->speed = pevent->link_state.speed; fcport->topology = pevent->link_state.topology; - if (fcport->topology == BFA_PORT_TOPOLOGY_LOOP) - fcport->myalpa = 0; + if (fcport->topology == BFA_PORT_TOPOLOGY_LOOP) { + bfa_fcport_update_loop_info(fcport, + &pevent->link_state.attr.loop_info); + return; + } /* QoS Details */ fcport->qos_attr = pevent->link_state.qos_attr; - fcport->qos_vc_attr = pevent->link_state.vc_fcf.qos_vc_attr; + fcport->qos_vc_attr = pevent->link_state.attr.vc_fcf.qos_vc_attr; /* * update trunk state if applicable @@ -3019,7 +3165,8 @@ bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) trunk->attr.state = BFA_TRUNK_DISABLED; /* update FCoE specific */ - fcport->fcoe_vlan = be16_to_cpu(pevent->link_state.vc_fcf.fcf.vlan); + fcport->fcoe_vlan = + be16_to_cpu(pevent->link_state.attr.vc_fcf.fcf.vlan); bfa_trc(fcport->bfa, fcport->speed); bfa_trc(fcport->bfa, fcport->topology); @@ -3453,6 +3600,7 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) case BFI_FCPORT_I2H_ENABLE_RSP: if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) { + fcport->stats_dma_ready = BFA_TRUE; if (fcport->use_flash_cfg) { fcport->cfg = i2hmsg.penable_rsp->port_cfg; fcport->cfg.maxfrsize = @@ -3468,6 +3616,8 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) else fcport->trunk.attr.state = BFA_TRUNK_DISABLED; + fcport->qos_attr.qos_bw = + i2hmsg.penable_rsp->port_cfg.qos_bw; fcport->use_flash_cfg = BFA_FALSE; } @@ -3476,6 +3626,9 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) else fcport->qos_attr.state = BFA_QOS_DISABLED; + fcport->qos_attr.qos_bw_op = + i2hmsg.penable_rsp->port_cfg.qos_bw; + bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); } break; @@ -3488,8 +3641,17 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) case BFI_FCPORT_I2H_EVENT: if (i2hmsg.event->link_state.linkstate == BFA_PORT_LINKUP) bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKUP); - else - bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKDOWN); + else { + if (i2hmsg.event->link_state.linkstate_rsn == + BFA_PORT_LINKSTATE_RSN_FAA_MISCONFIG) + bfa_sm_send_event(fcport, + BFA_FCPORT_SM_FAA_MISCONFIG); + else + bfa_sm_send_event(fcport, + BFA_FCPORT_SM_LINKDOWN); + } + fcport->qos_attr.qos_bw_op = + i2hmsg.event->link_state.qos_attr.qos_bw_op; break; case BFI_FCPORT_I2H_TRUNK_SCN: @@ -3609,6 +3771,9 @@ bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed) if (fcport->cfg.trunked == BFA_TRUE) return BFA_STATUS_TRUNK_ENABLED; + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (speed == BFA_PORT_SPEED_16GBPS)) + return BFA_STATUS_UNSUPP_SPEED; if ((speed != BFA_PORT_SPEED_AUTO) && (speed > fcport->speed_sup)) { bfa_trc(bfa, fcport->speed_sup); return BFA_STATUS_UNSUPP_SPEED; @@ -3663,7 +3828,26 @@ bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology topology) switch (topology) { case BFA_PORT_TOPOLOGY_P2P: + break; + case BFA_PORT_TOPOLOGY_LOOP: + if ((bfa_fcport_is_qos_enabled(bfa) != BFA_FALSE) || + (fcport->qos_attr.state != BFA_QOS_DISABLED)) + return BFA_STATUS_ERROR_QOS_ENABLED; + if (fcport->cfg.ratelimit != BFA_FALSE) + return BFA_STATUS_ERROR_TRL_ENABLED; + if ((bfa_fcport_is_trunk_enabled(bfa) != BFA_FALSE) || + (fcport->trunk.attr.state != BFA_TRUNK_DISABLED)) + return BFA_STATUS_ERROR_TRUNK_ENABLED; + if ((bfa_fcport_get_speed(bfa) == BFA_PORT_SPEED_16GBPS) || + (fcport->cfg.speed == BFA_PORT_SPEED_16GBPS)) + return BFA_STATUS_UNSUPP_SPEED; + if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) + return BFA_STATUS_LOOP_UNSUPP_MEZZ; + if (bfa_fcport_is_dport(bfa) != BFA_FALSE) + return BFA_STATUS_DPORT_ERR; + break; + case BFA_PORT_TOPOLOGY_AUTO: break; @@ -3686,6 +3870,17 @@ bfa_fcport_get_topology(struct bfa_s *bfa) return fcport->topology; } +/** + * Get config topology. + */ +enum bfa_port_topology +bfa_fcport_get_cfg_topology(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->cfg.topology; +} + bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa) { @@ -3761,9 +3956,11 @@ bfa_fcport_get_maxfrsize(struct bfa_s *bfa) u8 bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa) { - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + if (bfa_fcport_get_topology(bfa) != BFA_PORT_TOPOLOGY_LOOP) + return (BFA_FCPORT_MOD(bfa))->cfg.rx_bbcredit; - return fcport->cfg.rx_bbcredit; + else + return 0; } void @@ -3850,8 +4047,9 @@ bfa_fcport_get_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - if (bfa_ioc_is_disabled(&bfa->ioc)) - return BFA_STATUS_IOC_DISABLED; + if (!bfa_iocfc_is_operational(bfa) || + !fcport->stats_dma_ready) + return BFA_STATUS_IOC_NON_OP; if (!list_empty(&fcport->statsclr_pending_q)) return BFA_STATUS_DEVBUSY; @@ -3876,6 +4074,10 @@ bfa_fcport_clear_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + if (!bfa_iocfc_is_operational(bfa) || + !fcport->stats_dma_ready) + return BFA_STATUS_IOC_NON_OP; + if (!list_empty(&fcport->stats_pending_q)) return BFA_STATUS_DEVBUSY; @@ -3905,6 +4107,40 @@ bfa_fcport_is_disabled(struct bfa_s *bfa) } bfa_boolean_t +bfa_fcport_is_dport(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return (bfa_sm_to_state(hal_port_sm_table, fcport->sm) == + BFA_PORT_ST_DPORT); +} + +bfa_status_t +bfa_fcport_set_qos_bw(struct bfa_s *bfa, struct bfa_qos_bw_s *qos_bw) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa); + + bfa_trc(bfa, ioc_type); + + if ((qos_bw->high == 0) || (qos_bw->med == 0) || (qos_bw->low == 0)) + return BFA_STATUS_QOS_BW_INVALID; + + if ((qos_bw->high + qos_bw->med + qos_bw->low) != 100) + return BFA_STATUS_QOS_BW_INVALID; + + if ((qos_bw->med > qos_bw->high) || (qos_bw->low > qos_bw->med) || + (qos_bw->low > qos_bw->high)) + return BFA_STATUS_QOS_BW_INVALID; + + if ((ioc_type == BFA_IOC_TYPE_FC) && + (fcport->cfg.topology != BFA_PORT_TOPOLOGY_LOOP)) + fcport->cfg.qos_bw = *qos_bw; + + return BFA_STATUS_OK; +} + +bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); @@ -3981,6 +4217,26 @@ bfa_fcport_is_trunk_enabled(struct bfa_s *bfa) return fcport->cfg.trunked; } +void +bfa_fcport_dportenable(struct bfa_s *bfa) +{ + /* + * Assume caller check for port is in disable state + */ + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DPORTENABLE); + bfa_port_set_dportenabled(&bfa->modules.port, BFA_TRUE); +} + +void +bfa_fcport_dportdisable(struct bfa_s *bfa) +{ + /* + * Assume caller check for port is in disable state + */ + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DPORTDISABLE); + bfa_port_set_dportenabled(&bfa->modules.port, BFA_FALSE); +} + /* * Rport State machine functions */ @@ -4707,6 +4963,21 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN); break; + case BFI_RPORT_I2H_LIP_SCN_ONLINE: + bfa_fcport_update_loop_info(BFA_FCPORT_MOD(bfa), + &msg.lip_scn->loop_info); + bfa_cb_rport_scn_online(bfa); + break; + + case BFI_RPORT_I2H_LIP_SCN_OFFLINE: + bfa_cb_rport_scn_offline(bfa); + break; + + case BFI_RPORT_I2H_NO_DEV: + rp = BFA_RPORT_FROM_TAG(bfa, msg.lip_scn->bfa_handle); + bfa_cb_rport_scn_no_dev(rp->rport_drv); + break; + default: bfa_trc(bfa, m->mhdr.msg_id); WARN_ON(1); @@ -5348,6 +5619,37 @@ bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw) } /* + * Dport forward declaration + */ + +/* + * BFA DPORT state machine events + */ +enum bfa_dport_sm_event { + BFA_DPORT_SM_ENABLE = 1, /* dport enable event */ + BFA_DPORT_SM_DISABLE = 2, /* dport disable event */ + BFA_DPORT_SM_FWRSP = 3, /* fw enable/disable rsp */ + BFA_DPORT_SM_QRESUME = 4, /* CQ space available */ + BFA_DPORT_SM_HWFAIL = 5, /* IOC h/w failure */ +}; + +static void bfa_dport_sm_disabled(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event); +static void bfa_dport_sm_enabling_qwait(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event); +static void bfa_dport_sm_enabling(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event); +static void bfa_dport_sm_enabled(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event); +static void bfa_dport_sm_disabling_qwait(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event); +static void bfa_dport_sm_disabling(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event); +static void bfa_dport_qresume(void *cbarg); +static void bfa_dport_req_comp(struct bfa_dport_s *dport, + bfi_diag_dport_rsp_t *msg); + +/* * BFA fcdiag module */ #define BFA_DIAG_QTEST_TOV 1000 /* msec */ @@ -5377,15 +5679,24 @@ bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) { struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); + struct bfa_dport_s *dport = &fcdiag->dport; + fcdiag->bfa = bfa; fcdiag->trcmod = bfa->trcmod; /* The common DIAG attach bfa_diag_attach() will do all memory claim */ + dport->bfa = bfa; + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + bfa_reqq_winit(&dport->reqq_wait, bfa_dport_qresume, dport); + dport->cbfn = NULL; + dport->cbarg = NULL; } static void bfa_fcdiag_iocdisable(struct bfa_s *bfa) { struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); + struct bfa_dport_s *dport = &fcdiag->dport; + bfa_trc(fcdiag, fcdiag->lb.lock); if (fcdiag->lb.lock) { fcdiag->lb.status = BFA_STATUS_IOC_FAILURE; @@ -5393,6 +5704,8 @@ bfa_fcdiag_iocdisable(struct bfa_s *bfa) fcdiag->lb.lock = 0; bfa_fcdiag_set_busy_status(fcdiag); } + + bfa_sm_send_event(dport, BFA_DPORT_SM_HWFAIL); } static void @@ -5577,6 +5890,9 @@ bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg) case BFI_DIAG_I2H_QTEST: bfa_fcdiag_queuetest_comp(fcdiag, (bfi_diag_qtest_rsp_t *)msg); break; + case BFI_DIAG_I2H_DPORT: + bfa_dport_req_comp(&fcdiag->dport, (bfi_diag_dport_rsp_t *)msg); + break; default: bfa_trc(fcdiag, msg->mhdr.msg_id); WARN_ON(1); @@ -5646,12 +5962,18 @@ bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode, } } + /* + * For CT2, 1G is not supported + */ + if ((speed == BFA_PORT_SPEED_1GBPS) && + (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) { + bfa_trc(fcdiag, speed); + return BFA_STATUS_UNSUPP_SPEED; + } + /* For Mezz card, port speed entered needs to be checked */ if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) { if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) { - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; if (!(speed == BFA_PORT_SPEED_1GBPS || speed == BFA_PORT_SPEED_2GBPS || speed == BFA_PORT_SPEED_4GBPS || @@ -5764,3 +6086,379 @@ bfa_fcdiag_lb_is_running(struct bfa_s *bfa) struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); return fcdiag->lb.lock ? BFA_STATUS_DIAG_BUSY : BFA_STATUS_OK; } + +/* + * D-port + */ +static bfa_boolean_t bfa_dport_send_req(struct bfa_dport_s *dport, + enum bfi_dport_req req); +static void +bfa_cb_fcdiag_dport(struct bfa_dport_s *dport, bfa_status_t bfa_status) +{ + if (dport->cbfn != NULL) { + dport->cbfn(dport->cbarg, bfa_status); + dport->cbfn = NULL; + dport->cbarg = NULL; + } +} + +static void +bfa_dport_sm_disabled(struct bfa_dport_s *dport, enum bfa_dport_sm_event event) +{ + bfa_trc(dport->bfa, event); + + switch (event) { + case BFA_DPORT_SM_ENABLE: + bfa_fcport_dportenable(dport->bfa); + if (bfa_dport_send_req(dport, BFI_DPORT_ENABLE)) + bfa_sm_set_state(dport, bfa_dport_sm_enabling); + else + bfa_sm_set_state(dport, bfa_dport_sm_enabling_qwait); + break; + + case BFA_DPORT_SM_DISABLE: + /* Already disabled */ + break; + + case BFA_DPORT_SM_HWFAIL: + /* ignore */ + break; + + default: + bfa_sm_fault(dport->bfa, event); + } +} + +static void +bfa_dport_sm_enabling_qwait(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event) +{ + bfa_trc(dport->bfa, event); + + switch (event) { + case BFA_DPORT_SM_QRESUME: + bfa_sm_set_state(dport, bfa_dport_sm_enabling); + bfa_dport_send_req(dport, BFI_DPORT_ENABLE); + break; + + case BFA_DPORT_SM_HWFAIL: + bfa_reqq_wcancel(&dport->reqq_wait); + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + bfa_cb_fcdiag_dport(dport, BFA_STATUS_FAILED); + break; + + default: + bfa_sm_fault(dport->bfa, event); + } +} + +static void +bfa_dport_sm_enabling(struct bfa_dport_s *dport, enum bfa_dport_sm_event event) +{ + bfa_trc(dport->bfa, event); + + switch (event) { + case BFA_DPORT_SM_FWRSP: + bfa_sm_set_state(dport, bfa_dport_sm_enabled); + break; + + case BFA_DPORT_SM_HWFAIL: + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + bfa_cb_fcdiag_dport(dport, BFA_STATUS_FAILED); + break; + + default: + bfa_sm_fault(dport->bfa, event); + } +} + +static void +bfa_dport_sm_enabled(struct bfa_dport_s *dport, enum bfa_dport_sm_event event) +{ + bfa_trc(dport->bfa, event); + + switch (event) { + case BFA_DPORT_SM_ENABLE: + /* Already enabled */ + break; + + case BFA_DPORT_SM_DISABLE: + bfa_fcport_dportdisable(dport->bfa); + if (bfa_dport_send_req(dport, BFI_DPORT_DISABLE)) + bfa_sm_set_state(dport, bfa_dport_sm_disabling); + else + bfa_sm_set_state(dport, bfa_dport_sm_disabling_qwait); + break; + + case BFA_DPORT_SM_HWFAIL: + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + break; + + default: + bfa_sm_fault(dport->bfa, event); + } +} + +static void +bfa_dport_sm_disabling_qwait(struct bfa_dport_s *dport, + enum bfa_dport_sm_event event) +{ + bfa_trc(dport->bfa, event); + + switch (event) { + case BFA_DPORT_SM_QRESUME: + bfa_sm_set_state(dport, bfa_dport_sm_disabling); + bfa_dport_send_req(dport, BFI_DPORT_DISABLE); + break; + + case BFA_DPORT_SM_HWFAIL: + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + bfa_reqq_wcancel(&dport->reqq_wait); + bfa_cb_fcdiag_dport(dport, BFA_STATUS_OK); + break; + + default: + bfa_sm_fault(dport->bfa, event); + } +} + +static void +bfa_dport_sm_disabling(struct bfa_dport_s *dport, enum bfa_dport_sm_event event) +{ + bfa_trc(dport->bfa, event); + + switch (event) { + case BFA_DPORT_SM_FWRSP: + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + break; + + case BFA_DPORT_SM_HWFAIL: + bfa_sm_set_state(dport, bfa_dport_sm_disabled); + bfa_cb_fcdiag_dport(dport, BFA_STATUS_OK); + break; + + default: + bfa_sm_fault(dport->bfa, event); + } +} + + +static bfa_boolean_t +bfa_dport_send_req(struct bfa_dport_s *dport, enum bfi_dport_req req) +{ + struct bfi_diag_dport_req_s *m; + + /* + * Increment message tag before queue check, so that responses to old + * requests are discarded. + */ + dport->msgtag++; + + /* + * check for room in queue to send request now + */ + m = bfa_reqq_next(dport->bfa, BFA_REQQ_DIAG); + if (!m) { + bfa_reqq_wait(dport->bfa, BFA_REQQ_PORT, &dport->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_DIAG, BFI_DIAG_H2I_DPORT, + bfa_fn_lpu(dport->bfa)); + m->req = req; + m->msgtag = dport->msgtag; + + /* + * queue I/O message to firmware + */ + bfa_reqq_produce(dport->bfa, BFA_REQQ_DIAG, m->mh); + + return BFA_TRUE; +} + +static void +bfa_dport_qresume(void *cbarg) +{ + struct bfa_dport_s *dport = cbarg; + + bfa_sm_send_event(dport, BFA_DPORT_SM_QRESUME); +} + +static void +bfa_dport_req_comp(struct bfa_dport_s *dport, bfi_diag_dport_rsp_t *msg) +{ + bfa_sm_send_event(dport, BFA_DPORT_SM_FWRSP); + bfa_cb_fcdiag_dport(dport, msg->status); +} + +/* + * Dport enable + * + * @param[in] *bfa - bfa data struct + */ +bfa_status_t +bfa_dport_enable(struct bfa_s *bfa, bfa_cb_diag_t cbfn, void *cbarg) +{ + struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); + struct bfa_dport_s *dport = &fcdiag->dport; + + /* + * Dport is not support in MEZZ card + */ + if (bfa_mfg_is_mezz(dport->bfa->ioc.attr->card_type)) { + bfa_trc(dport->bfa, BFA_STATUS_PBC); + return BFA_STATUS_CMD_NOTSUPP_MEZZ; + } + + /* + * Check to see if IOC is down + */ + if (!bfa_iocfc_is_operational(bfa)) + return BFA_STATUS_IOC_NON_OP; + + /* if port is PBC disabled, return error */ + if (bfa_fcport_is_pbcdisabled(bfa)) { + bfa_trc(dport->bfa, BFA_STATUS_PBC); + return BFA_STATUS_PBC; + } + + /* + * Check if port mode is FC port + */ + if (bfa_ioc_get_type(&bfa->ioc) != BFA_IOC_TYPE_FC) { + bfa_trc(dport->bfa, bfa_ioc_get_type(&bfa->ioc)); + return BFA_STATUS_CMD_NOTSUPP_CNA; + } + + /* + * Check if port is in LOOP mode + */ + if ((bfa_fcport_get_cfg_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) || + (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP)) { + bfa_trc(dport->bfa, 0); + return BFA_STATUS_TOPOLOGY_LOOP; + } + + /* + * Check if port is TRUNK mode + */ + if (bfa_fcport_is_trunk_enabled(bfa)) { + bfa_trc(dport->bfa, 0); + return BFA_STATUS_ERROR_TRUNK_ENABLED; + } + + /* + * Check to see if port is disable or in dport state + */ + if ((bfa_fcport_is_disabled(bfa) == BFA_FALSE) && + (bfa_fcport_is_dport(bfa) == BFA_FALSE)) { + bfa_trc(dport->bfa, 0); + return BFA_STATUS_PORT_NOT_DISABLED; + } + + /* + * Check if dport is busy + */ + if (bfa_sm_cmp_state(dport, bfa_dport_sm_enabling) || + bfa_sm_cmp_state(dport, bfa_dport_sm_enabling_qwait) || + bfa_sm_cmp_state(dport, bfa_dport_sm_disabling) || + bfa_sm_cmp_state(dport, bfa_dport_sm_disabling_qwait)) { + return BFA_STATUS_DEVBUSY; + } + + /* + * Check if dport is already enabled + */ + if (bfa_sm_cmp_state(dport, bfa_dport_sm_enabled)) { + bfa_trc(dport->bfa, 0); + return BFA_STATUS_DPORT_ENABLED; + } + + dport->cbfn = cbfn; + dport->cbarg = cbarg; + + bfa_sm_send_event(dport, BFA_DPORT_SM_ENABLE); + return BFA_STATUS_OK; +} + +/* + * Dport disable + * + * @param[in] *bfa - bfa data struct + */ +bfa_status_t +bfa_dport_disable(struct bfa_s *bfa, bfa_cb_diag_t cbfn, void *cbarg) +{ + struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); + struct bfa_dport_s *dport = &fcdiag->dport; + + if (bfa_ioc_is_disabled(&bfa->ioc)) + return BFA_STATUS_IOC_DISABLED; + + /* if port is PBC disabled, return error */ + if (bfa_fcport_is_pbcdisabled(bfa)) { + bfa_trc(dport->bfa, BFA_STATUS_PBC); + return BFA_STATUS_PBC; + } + + /* + * Check to see if port is disable or in dport state + */ + if ((bfa_fcport_is_disabled(bfa) == BFA_FALSE) && + (bfa_fcport_is_dport(bfa) == BFA_FALSE)) { + bfa_trc(dport->bfa, 0); + return BFA_STATUS_PORT_NOT_DISABLED; + } + + /* + * Check if dport is busy + */ + if (bfa_sm_cmp_state(dport, bfa_dport_sm_enabling) || + bfa_sm_cmp_state(dport, bfa_dport_sm_enabling_qwait) || + bfa_sm_cmp_state(dport, bfa_dport_sm_disabling) || + bfa_sm_cmp_state(dport, bfa_dport_sm_disabling_qwait)) + return BFA_STATUS_DEVBUSY; + + /* + * Check if dport is already disabled + */ + if (bfa_sm_cmp_state(dport, bfa_dport_sm_disabled)) { + bfa_trc(dport->bfa, 0); + return BFA_STATUS_DPORT_DISABLED; + } + + dport->cbfn = cbfn; + dport->cbarg = cbarg; + + bfa_sm_send_event(dport, BFA_DPORT_SM_DISABLE); + return BFA_STATUS_OK; +} + +/* + * Get D-port state + * + * @param[in] *bfa - bfa data struct + */ + +bfa_status_t +bfa_dport_get_state(struct bfa_s *bfa, enum bfa_dport_state *state) +{ + struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); + struct bfa_dport_s *dport = &fcdiag->dport; + + if (bfa_sm_cmp_state(dport, bfa_dport_sm_enabled)) + *state = BFA_DPORT_ST_ENABLED; + else if (bfa_sm_cmp_state(dport, bfa_dport_sm_enabling) || + bfa_sm_cmp_state(dport, bfa_dport_sm_enabling_qwait)) + *state = BFA_DPORT_ST_ENABLING; + else if (bfa_sm_cmp_state(dport, bfa_dport_sm_disabled)) + *state = BFA_DPORT_ST_DISABLED; + else if (bfa_sm_cmp_state(dport, bfa_dport_sm_disabling) || + bfa_sm_cmp_state(dport, bfa_dport_sm_disabling_qwait)) + *state = BFA_DPORT_ST_DISABLING; + else { + bfa_trc(dport->bfa, BFA_STATUS_EINVAL); + return BFA_STATUS_EINVAL; + } + return BFA_STATUS_OK; +} diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 1abcf7c51661..8d7fbecfcb22 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -474,8 +474,10 @@ struct bfa_fcport_s { /* supported speeds */ enum bfa_port_speed speed; /* current speed */ enum bfa_port_topology topology; /* current topology */ - u8 myalpa; /* my ALPA in LOOP topology */ u8 rsvd[3]; + u8 myalpa; /* my ALPA in LOOP topology */ + u8 alpabm_valid; /* alpa bitmap valid or not */ + struct fc_alpabm_s alpabm; /* alpa bitmap */ struct bfa_port_cfg_s cfg; /* current port configuration */ bfa_boolean_t use_flash_cfg; /* get port cfg from flash */ struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ @@ -512,6 +514,7 @@ struct bfa_fcport_s { struct bfa_fcport_trunk_s trunk; u16 fcoe_vlan; struct bfa_mem_dma_s fcport_dma; + bfa_boolean_t stats_dma_ready; }; #define BFA_FCPORT_MOD(__bfa) (&(__bfa)->modules.fcport) @@ -534,6 +537,7 @@ enum bfa_port_speed bfa_fcport_get_speed(struct bfa_s *bfa); bfa_status_t bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology topo); enum bfa_port_topology bfa_fcport_get_topology(struct bfa_s *bfa); +enum bfa_port_topology bfa_fcport_get_cfg_topology(struct bfa_s *bfa); bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa); bfa_boolean_t bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa); u8 bfa_fcport_get_myalpa(struct bfa_s *bfa); @@ -547,6 +551,9 @@ void bfa_fcport_event_register(struct bfa_s *bfa, void (*event_cbfn) (void *cbarg, enum bfa_port_linkstate event), void *event_cbarg); bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa); +bfa_boolean_t bfa_fcport_is_dport(struct bfa_s *bfa); +bfa_status_t bfa_fcport_set_qos_bw(struct bfa_s *bfa, + struct bfa_qos_bw_s *qos_bw); enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa); void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn); @@ -560,6 +567,8 @@ bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb); bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa); bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa); +void bfa_fcport_dportenable(struct bfa_s *bfa); +void bfa_fcport_dportdisable(struct bfa_s *bfa); bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa); void bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state); @@ -575,6 +584,9 @@ void bfa_cb_rport_offline(void *rport); void bfa_cb_rport_qos_scn_flowid(void *rport, struct bfa_rport_qos_attr_s old_qos_attr, struct bfa_rport_qos_attr_s new_qos_attr); +void bfa_cb_rport_scn_online(struct bfa_s *bfa); +void bfa_cb_rport_scn_offline(struct bfa_s *bfa); +void bfa_cb_rport_scn_no_dev(void *rp); void bfa_cb_rport_qos_scn_prio(void *rport, struct bfa_rport_qos_attr_s old_qos_attr, struct bfa_rport_qos_attr_s new_qos_attr); @@ -697,11 +709,21 @@ struct bfa_fcdiag_lb_s { u32 status; }; +struct bfa_dport_s { + struct bfa_s *bfa; /* Back pointer to BFA */ + bfa_sm_t sm; /* finite state machine */ + u32 msgtag; /* firmware msg tag for reply */ + struct bfa_reqq_wait_s reqq_wait; + bfa_cb_diag_t cbfn; + void *cbarg; +}; + struct bfa_fcdiag_s { struct bfa_s *bfa; /* Back pointer to BFA */ struct bfa_trc_mod_s *trcmod; struct bfa_fcdiag_lb_s lb; struct bfa_fcdiag_qtest_s qtest; + struct bfa_dport_s dport; }; #define BFA_FCDIAG_MOD(__bfa) (&(__bfa)->modules.fcdiag) @@ -717,5 +739,11 @@ bfa_status_t bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 ignore, u32 queue, struct bfa_diag_qtest_result_s *result, bfa_cb_diag_t cbfn, void *cbarg); bfa_status_t bfa_fcdiag_lb_is_running(struct bfa_s *bfa); +bfa_status_t bfa_dport_enable(struct bfa_s *bfa, bfa_cb_diag_t cbfn, + void *cbarg); +bfa_status_t bfa_dport_disable(struct bfa_s *bfa, bfa_cb_diag_t cbfn, + void *cbarg); +bfa_status_t bfa_dport_get_state(struct bfa_s *bfa, + enum bfa_dport_state *state); #endif /* __BFA_SVC_H__ */ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index c37494916a1a..895b0e516e07 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -63,9 +63,9 @@ int max_rport_logins = BFA_FCS_MAX_RPORT_LOGINS; u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size; u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2; -#define BFAD_FW_FILE_CB "cbfw.bin" -#define BFAD_FW_FILE_CT "ctfw.bin" -#define BFAD_FW_FILE_CT2 "ct2fw.bin" +#define BFAD_FW_FILE_CB "cbfw-3.1.0.0.bin" +#define BFAD_FW_FILE_CT "ctfw-3.1.0.0.bin" +#define BFAD_FW_FILE_CT2 "ct2fw-3.1.0.0.bin" static u32 *bfad_load_fwimg(struct pci_dev *pdev); static void bfad_free_fwimg(void); diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 0afa39076cef..555e7db94a1c 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -33,7 +33,7 @@ bfad_iocmd_ioc_enable(struct bfad_s *bfad, void *cmd) /* If IOC is not in disabled state - return */ if (!bfa_ioc_is_disabled(&bfad->bfa.ioc)) { spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_IOC_FAILURE; + iocmd->status = BFA_STATUS_OK; return rc; } @@ -54,6 +54,12 @@ bfad_iocmd_ioc_disable(struct bfad_s *bfad, void *cmd) unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); + if (bfa_ioc_is_disabled(&bfad->bfa.ioc)) { + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + iocmd->status = BFA_STATUS_OK; + return rc; + } + if (bfad->disable_active) { spin_unlock_irqrestore(&bfad->bfad_lock, flags); return -EBUSY; @@ -101,9 +107,10 @@ bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd) /* set adapter hw path */ strcpy(iocmd->adapter_hwpath, bfad->pci_name); - i = strlen(iocmd->adapter_hwpath) - 1; - while (iocmd->adapter_hwpath[i] != '.') - i--; + for (i = 0; iocmd->adapter_hwpath[i] != ':' && i < BFA_STRING_32; i++) + ; + for (; iocmd->adapter_hwpath[++i] != ':' && i < BFA_STRING_32; ) + ; iocmd->adapter_hwpath[i] = '\0'; iocmd->status = BFA_STATUS_OK; return 0; @@ -880,6 +887,19 @@ out: } int +bfad_iocmd_qos_set_bw(struct bfad_s *bfad, void *pcmd) +{ + struct bfa_bsg_qos_bw_s *iocmd = (struct bfa_bsg_qos_bw_s *)pcmd; + unsigned long flags; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fcport_set_qos_bw(&bfad->bfa, &iocmd->qos_bw); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return 0; +} + +int bfad_iocmd_ratelim(struct bfad_s *bfad, unsigned int cmd, void *pcmd) { struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; @@ -888,16 +908,22 @@ bfad_iocmd_ratelim(struct bfad_s *bfad, unsigned int cmd, void *pcmd) spin_lock_irqsave(&bfad->bfad_lock, flags); - if (cmd == IOCMD_RATELIM_ENABLE) - fcport->cfg.ratelimit = BFA_TRUE; - else if (cmd == IOCMD_RATELIM_DISABLE) - fcport->cfg.ratelimit = BFA_FALSE; + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else { + if (cmd == IOCMD_RATELIM_ENABLE) + fcport->cfg.ratelimit = BFA_TRUE; + else if (cmd == IOCMD_RATELIM_DISABLE) + fcport->cfg.ratelimit = BFA_FALSE; - if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN) - fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS; + if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN) + fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS; + + iocmd->status = BFA_STATUS_OK; + } spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; return 0; } @@ -919,8 +945,13 @@ bfad_iocmd_ratelim_speed(struct bfad_s *bfad, unsigned int cmd, void *pcmd) return 0; } - fcport->cfg.trl_def_speed = iocmd->speed; - iocmd->status = BFA_STATUS_OK; + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else { + fcport->cfg.trl_def_speed = iocmd->speed; + iocmd->status = BFA_STATUS_OK; + } spin_unlock_irqrestore(&bfad->bfad_lock, flags); return 0; @@ -1167,8 +1198,8 @@ bfad_iocmd_pcifn_create(struct bfad_s *bfad, void *cmd) spin_lock_irqsave(&bfad->bfad_lock, flags); iocmd->status = bfa_ablk_pf_create(&bfad->bfa.modules.ablk, &iocmd->pcifn_id, iocmd->port, - iocmd->pcifn_class, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); + iocmd->pcifn_class, iocmd->bw_min, + iocmd->bw_max, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (iocmd->status != BFA_STATUS_OK) goto out; @@ -1211,8 +1242,8 @@ bfad_iocmd_pcifn_bw(struct bfad_s *bfad, void *cmd) init_completion(&fcomp.comp); spin_lock_irqsave(&bfad->bfad_lock, flags); iocmd->status = bfa_ablk_pf_update(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); + iocmd->pcifn_id, iocmd->bw_min, + iocmd->bw_max, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfa_trc(bfad, iocmd->status); if (iocmd->status != BFA_STATUS_OK) @@ -1736,6 +1767,52 @@ bfad_iocmd_diag_lb_stat(struct bfad_s *bfad, void *cmd) } int +bfad_iocmd_diag_cfg_dport(struct bfad_s *bfad, unsigned int cmd, void *pcmd) +{ + struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; + unsigned long flags; + struct bfad_hal_comp fcomp; + + init_completion(&fcomp.comp); + spin_lock_irqsave(&bfad->bfad_lock, flags); + if (cmd == IOCMD_DIAG_DPORT_ENABLE) + iocmd->status = bfa_dport_enable(&bfad->bfa, + bfad_hcb_comp, &fcomp); + else if (cmd == IOCMD_DIAG_DPORT_DISABLE) + iocmd->status = bfa_dport_disable(&bfad->bfa, + bfad_hcb_comp, &fcomp); + else { + bfa_trc(bfad, 0); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + if (iocmd->status != BFA_STATUS_OK) + bfa_trc(bfad, iocmd->status); + else { + wait_for_completion(&fcomp.comp); + iocmd->status = fcomp.status; + } + + return 0; +} + +int +bfad_iocmd_diag_dport_get_state(struct bfad_s *bfad, void *pcmd) +{ + struct bfa_bsg_diag_dport_get_state_s *iocmd = + (struct bfa_bsg_diag_dport_get_state_s *)pcmd; + unsigned long flags; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_dport_get_state(&bfad->bfa, &iocmd->state); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return 0; +} + +int bfad_iocmd_phy_get_attr(struct bfad_s *bfad, void *cmd) { struct bfa_bsg_phy_attr_s *iocmd = @@ -2052,7 +2129,7 @@ bfad_iocmd_boot_cfg(struct bfad_s *bfad, void *cmd) init_completion(&fcomp.comp); spin_lock_irqsave(&bfad->bfad_lock, flags); iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa), - BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn), + BFA_FLASH_PART_BOOT, bfad->bfa.ioc.port_id, &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -2074,7 +2151,7 @@ bfad_iocmd_boot_query(struct bfad_s *bfad, void *cmd) init_completion(&fcomp.comp); spin_lock_irqsave(&bfad->bfad_lock, flags); iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa), - BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn), + BFA_FLASH_PART_BOOT, bfad->bfa.ioc.port_id, &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -2161,22 +2238,31 @@ bfad_iocmd_cfg_trunk(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_TRUNK_ENABLE) { - trunk->attr.state = BFA_TRUNK_OFFLINE; - bfa_fcport_disable(&bfad->bfa); - fcport->cfg.trunked = BFA_TRUE; - } else if (v_cmd == IOCMD_TRUNK_DISABLE) { - trunk->attr.state = BFA_TRUNK_DISABLED; - bfa_fcport_disable(&bfad->bfa); - fcport->cfg.trunked = BFA_FALSE; - } + if (bfa_fcport_is_dport(&bfad->bfa)) + return BFA_STATUS_DPORT_ERR; - if (!bfa_fcport_is_disabled(&bfad->bfa)) - bfa_fcport_enable(&bfad->bfa); + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) || + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else { + if (v_cmd == IOCMD_TRUNK_ENABLE) { + trunk->attr.state = BFA_TRUNK_OFFLINE; + bfa_fcport_disable(&bfad->bfa); + fcport->cfg.trunked = BFA_TRUE; + } else if (v_cmd == IOCMD_TRUNK_DISABLE) { + trunk->attr.state = BFA_TRUNK_DISABLED; + bfa_fcport_disable(&bfad->bfa); + fcport->cfg.trunked = BFA_FALSE; + } + + if (!bfa_fcport_is_disabled(&bfad->bfa)) + bfa_fcport_enable(&bfad->bfa); + + iocmd->status = BFA_STATUS_OK; + } spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; return 0; } @@ -2189,12 +2275,17 @@ bfad_iocmd_trunk_get_attr(struct bfad_s *bfad, void *cmd) unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); - memcpy((void *)&iocmd->attr, (void *)&trunk->attr, - sizeof(struct bfa_trunk_attr_s)); - iocmd->attr.port_id = bfa_lps_get_base_pid(&bfad->bfa); + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) || + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else { + memcpy((void *)&iocmd->attr, (void *)&trunk->attr, + sizeof(struct bfa_trunk_attr_s)); + iocmd->attr.port_id = bfa_lps_get_base_pid(&bfad->bfa); + iocmd->status = BFA_STATUS_OK; + } spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; return 0; } @@ -2207,14 +2298,22 @@ bfad_iocmd_qos(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) spin_lock_irqsave(&bfad->bfad_lock, flags); if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) { - if (v_cmd == IOCMD_QOS_ENABLE) - fcport->cfg.qos_enabled = BFA_TRUE; - else if (v_cmd == IOCMD_QOS_DISABLE) - fcport->cfg.qos_enabled = BFA_FALSE; + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else { + if (v_cmd == IOCMD_QOS_ENABLE) + fcport->cfg.qos_enabled = BFA_TRUE; + else if (v_cmd == IOCMD_QOS_DISABLE) { + fcport->cfg.qos_enabled = BFA_FALSE; + fcport->cfg.qos_bw.high = BFA_QOS_BW_HIGH; + fcport->cfg.qos_bw.med = BFA_QOS_BW_MED; + fcport->cfg.qos_bw.low = BFA_QOS_BW_LOW; + } + } } spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; return 0; } @@ -2226,11 +2325,21 @@ bfad_iocmd_qos_get_attr(struct bfad_s *bfad, void *cmd) unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->attr.state = fcport->qos_attr.state; - iocmd->attr.total_bb_cr = be32_to_cpu(fcport->qos_attr.total_bb_cr); + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else { + iocmd->attr.state = fcport->qos_attr.state; + iocmd->attr.total_bb_cr = + be32_to_cpu(fcport->qos_attr.total_bb_cr); + iocmd->attr.qos_bw.high = fcport->cfg.qos_bw.high; + iocmd->attr.qos_bw.med = fcport->cfg.qos_bw.med; + iocmd->attr.qos_bw.low = fcport->cfg.qos_bw.low; + iocmd->attr.qos_bw_op = fcport->qos_attr.qos_bw_op; + iocmd->status = BFA_STATUS_OK; + } spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; return 0; } @@ -2274,6 +2383,7 @@ bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd) struct bfad_hal_comp fcomp; unsigned long flags; struct bfa_cb_pending_q_s cb_qe; + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); init_completion(&fcomp.comp); bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, @@ -2281,7 +2391,11 @@ bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd) spin_lock_irqsave(&bfad->bfad_lock, flags); WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); - iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe); + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else + iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (iocmd->status != BFA_STATUS_OK) { bfa_trc(bfad, iocmd->status); @@ -2300,6 +2414,7 @@ bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd) struct bfad_hal_comp fcomp; unsigned long flags; struct bfa_cb_pending_q_s cb_qe; + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); init_completion(&fcomp.comp); bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, @@ -2307,7 +2422,11 @@ bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd) spin_lock_irqsave(&bfad->bfad_lock, flags); WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); - iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe); + if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) && + (fcport->topology == BFA_PORT_TOPOLOGY_LOOP)) + iocmd->status = BFA_STATUS_TOPOLOGY_LOOP; + else + iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (iocmd->status != BFA_STATUS_OK) { bfa_trc(bfad, iocmd->status); @@ -2435,6 +2554,139 @@ bfad_iocmd_fcpim_cfg_lunmask(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) return 0; } +int +bfad_iocmd_fcpim_throttle_query(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_fcpim_throttle_s *iocmd = + (struct bfa_bsg_fcpim_throttle_s *)cmd; + unsigned long flags; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fcpim_throttle_get(&bfad->bfa, + (void *)&iocmd->throttle); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return 0; +} + +int +bfad_iocmd_fcpim_throttle_set(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_fcpim_throttle_s *iocmd = + (struct bfa_bsg_fcpim_throttle_s *)cmd; + unsigned long flags; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fcpim_throttle_set(&bfad->bfa, + iocmd->throttle.cfg_value); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return 0; +} + +int +bfad_iocmd_tfru_read(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_tfru_s *iocmd = + (struct bfa_bsg_tfru_s *)cmd; + struct bfad_hal_comp fcomp; + unsigned long flags = 0; + + init_completion(&fcomp.comp); + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_tfru_read(BFA_FRU(&bfad->bfa), + &iocmd->data, iocmd->len, iocmd->offset, + bfad_hcb_comp, &fcomp); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (iocmd->status == BFA_STATUS_OK) { + wait_for_completion(&fcomp.comp); + iocmd->status = fcomp.status; + } + + return 0; +} + +int +bfad_iocmd_tfru_write(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_tfru_s *iocmd = + (struct bfa_bsg_tfru_s *)cmd; + struct bfad_hal_comp fcomp; + unsigned long flags = 0; + + init_completion(&fcomp.comp); + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_tfru_write(BFA_FRU(&bfad->bfa), + &iocmd->data, iocmd->len, iocmd->offset, + bfad_hcb_comp, &fcomp); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (iocmd->status == BFA_STATUS_OK) { + wait_for_completion(&fcomp.comp); + iocmd->status = fcomp.status; + } + + return 0; +} + +int +bfad_iocmd_fruvpd_read(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_fruvpd_s *iocmd = + (struct bfa_bsg_fruvpd_s *)cmd; + struct bfad_hal_comp fcomp; + unsigned long flags = 0; + + init_completion(&fcomp.comp); + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fruvpd_read(BFA_FRU(&bfad->bfa), + &iocmd->data, iocmd->len, iocmd->offset, + bfad_hcb_comp, &fcomp); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (iocmd->status == BFA_STATUS_OK) { + wait_for_completion(&fcomp.comp); + iocmd->status = fcomp.status; + } + + return 0; +} + +int +bfad_iocmd_fruvpd_update(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_fruvpd_s *iocmd = + (struct bfa_bsg_fruvpd_s *)cmd; + struct bfad_hal_comp fcomp; + unsigned long flags = 0; + + init_completion(&fcomp.comp); + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fruvpd_update(BFA_FRU(&bfad->bfa), + &iocmd->data, iocmd->len, iocmd->offset, + bfad_hcb_comp, &fcomp); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (iocmd->status == BFA_STATUS_OK) { + wait_for_completion(&fcomp.comp); + iocmd->status = fcomp.status; + } + + return 0; +} + +int +bfad_iocmd_fruvpd_get_max_size(struct bfad_s *bfad, void *cmd) +{ + struct bfa_bsg_fruvpd_max_size_s *iocmd = + (struct bfa_bsg_fruvpd_max_size_s *)cmd; + unsigned long flags = 0; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fruvpd_get_max_size(BFA_FRU(&bfad->bfa), + &iocmd->max_size); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return 0; +} + static int bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, unsigned int payload_len) @@ -2660,6 +2912,13 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, case IOCMD_DIAG_LB_STAT: rc = bfad_iocmd_diag_lb_stat(bfad, iocmd); break; + case IOCMD_DIAG_DPORT_ENABLE: + case IOCMD_DIAG_DPORT_DISABLE: + rc = bfad_iocmd_diag_cfg_dport(bfad, cmd, iocmd); + break; + case IOCMD_DIAG_DPORT_GET_STATE: + rc = bfad_iocmd_diag_dport_get_state(bfad, iocmd); + break; case IOCMD_PHY_GET_ATTR: rc = bfad_iocmd_phy_get_attr(bfad, iocmd); break; @@ -2741,6 +3000,9 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, case IOCMD_QOS_RESET_STATS: rc = bfad_iocmd_qos_reset_stats(bfad, iocmd); break; + case IOCMD_QOS_SET_BW: + rc = bfad_iocmd_qos_set_bw(bfad, iocmd); + break; case IOCMD_VF_GET_STATS: rc = bfad_iocmd_vf_get_stats(bfad, iocmd); break; @@ -2759,6 +3021,29 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, case IOCMD_FCPIM_LUNMASK_DELETE: rc = bfad_iocmd_fcpim_cfg_lunmask(bfad, iocmd, cmd); break; + case IOCMD_FCPIM_THROTTLE_QUERY: + rc = bfad_iocmd_fcpim_throttle_query(bfad, iocmd); + break; + case IOCMD_FCPIM_THROTTLE_SET: + rc = bfad_iocmd_fcpim_throttle_set(bfad, iocmd); + break; + /* TFRU */ + case IOCMD_TFRU_READ: + rc = bfad_iocmd_tfru_read(bfad, iocmd); + break; + case IOCMD_TFRU_WRITE: + rc = bfad_iocmd_tfru_write(bfad, iocmd); + break; + /* FRU */ + case IOCMD_FRUVPD_READ: + rc = bfad_iocmd_fruvpd_read(bfad, iocmd); + break; + case IOCMD_FRUVPD_UPDATE: + rc = bfad_iocmd_fruvpd_update(bfad, iocmd); + break; + case IOCMD_FRUVPD_GET_MAX_SIZE: + rc = bfad_iocmd_fruvpd_get_max_size(bfad, iocmd); + break; default: rc = -EINVAL; break; diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h index 8c569ddb750d..15e1fc8e796b 100644 --- a/drivers/scsi/bfa/bfad_bsg.h +++ b/drivers/scsi/bfa/bfad_bsg.h @@ -141,6 +141,17 @@ enum { IOCMD_FCPIM_LUNMASK_QUERY, IOCMD_FCPIM_LUNMASK_ADD, IOCMD_FCPIM_LUNMASK_DELETE, + IOCMD_DIAG_DPORT_ENABLE, + IOCMD_DIAG_DPORT_DISABLE, + IOCMD_DIAG_DPORT_GET_STATE, + IOCMD_QOS_SET_BW, + IOCMD_FCPIM_THROTTLE_QUERY, + IOCMD_FCPIM_THROTTLE_SET, + IOCMD_TFRU_READ, + IOCMD_TFRU_WRITE, + IOCMD_FRUVPD_READ, + IOCMD_FRUVPD_UPDATE, + IOCMD_FRUVPD_GET_MAX_SIZE, }; struct bfa_bsg_gen_s { @@ -463,7 +474,8 @@ struct bfa_bsg_pcifn_s { bfa_status_t status; u16 bfad_num; u16 pcifn_id; - u32 bandwidth; + u16 bw_min; + u16 bw_max; u8 port; enum bfi_pcifn_class pcifn_class; u8 rsvd[1]; @@ -613,6 +625,13 @@ struct bfa_bsg_diag_lb_stat_s { u16 rsvd; }; +struct bfa_bsg_diag_dport_get_state_s { + bfa_status_t status; + u16 bfad_num; + u16 rsvd; + enum bfa_dport_state state; +}; + struct bfa_bsg_phy_attr_s { bfa_status_t status; u16 bfad_num; @@ -694,6 +713,13 @@ struct bfa_bsg_qos_vc_attr_s { struct bfa_qos_vc_attr_s attr; }; +struct bfa_bsg_qos_bw_s { + bfa_status_t status; + u16 bfad_num; + u16 rsvd; + struct bfa_qos_bw_s qos_bw; +}; + struct bfa_bsg_vf_stats_s { bfa_status_t status; u16 bfad_num; @@ -722,6 +748,41 @@ struct bfa_bsg_fcpim_lunmask_s { struct scsi_lun lun; }; +struct bfa_bsg_fcpim_throttle_s { + bfa_status_t status; + u16 bfad_num; + u16 vf_id; + struct bfa_defs_fcpim_throttle_s throttle; +}; + +#define BFA_TFRU_DATA_SIZE 64 +#define BFA_MAX_FRUVPD_TRANSFER_SIZE 0x1000 + +struct bfa_bsg_tfru_s { + bfa_status_t status; + u16 bfad_num; + u16 rsvd; + u32 offset; + u32 len; + u8 data[BFA_TFRU_DATA_SIZE]; +}; + +struct bfa_bsg_fruvpd_s { + bfa_status_t status; + u16 bfad_num; + u16 rsvd; + u32 offset; + u32 len; + u8 data[BFA_MAX_FRUVPD_TRANSFER_SIZE]; +}; + +struct bfa_bsg_fruvpd_max_size_s { + bfa_status_t status; + u16 bfad_num; + u16 rsvd; + u32 max_size; +}; + struct bfa_bsg_fcpt_s { bfa_status_t status; u16 vf_id; diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 1840651ce1d4..0c64a04f01fa 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -57,7 +57,7 @@ #ifdef BFA_DRIVER_VERSION #define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION #else -#define BFAD_DRIVER_VERSION "3.1.2.0" +#define BFAD_DRIVER_VERSION "3.1.2.1" #endif #define BFAD_PROTO_NAME FCPI_NAME diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h index b2ba0b2e91b2..57b146bca18c 100644 --- a/drivers/scsi/bfa/bfi.h +++ b/drivers/scsi/bfa/bfi.h @@ -210,7 +210,8 @@ enum bfi_mclass { BFI_MC_PORT = 21, /* Physical port */ BFI_MC_SFP = 22, /* SFP module */ BFI_MC_PHY = 25, /* External PHY message class */ - BFI_MC_MAX = 32 + BFI_MC_FRU = 34, + BFI_MC_MAX = 35 }; #define BFI_IOC_MAX_CQS 4 @@ -288,6 +289,9 @@ struct bfi_ioc_attr_s { char optrom_version[BFA_VERSION_LEN]; struct bfa_mfg_vpd_s vpd; u32 card_type; /* card type */ + u8 mfg_day; /* manufacturing day */ + u8 mfg_month; /* manufacturing month */ + u16 mfg_year; /* manufacturing year */ }; /* @@ -687,7 +691,8 @@ struct bfi_ablk_h2i_pf_req_s { u8 pcifn; u8 port; u16 pers; - u32 bw; + u16 bw_min; /* percent BW @ max speed */ + u16 bw_max; /* percent BW @ max speed */ }; /* BFI_ABLK_H2I_OPTROM_ENABLE, BFI_ABLK_H2I_OPTROM_DISABLE */ @@ -957,6 +962,7 @@ enum bfi_diag_h2i { BFI_DIAG_H2I_TEMPSENSOR = 4, BFI_DIAG_H2I_LEDTEST = 5, BFI_DIAG_H2I_QTEST = 6, + BFI_DIAG_H2I_DPORT = 7, }; enum bfi_diag_i2h { @@ -966,6 +972,7 @@ enum bfi_diag_i2h { BFI_DIAG_I2H_TEMPSENSOR = BFA_I2HM(BFI_DIAG_H2I_TEMPSENSOR), BFI_DIAG_I2H_LEDTEST = BFA_I2HM(BFI_DIAG_H2I_LEDTEST), BFI_DIAG_I2H_QTEST = BFA_I2HM(BFI_DIAG_H2I_QTEST), + BFI_DIAG_I2H_DPORT = BFA_I2HM(BFI_DIAG_H2I_DPORT), }; #define BFI_DIAG_MAX_SGES 2 @@ -1052,6 +1059,23 @@ struct bfi_diag_qtest_req_s { #define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s /* + * D-port test + */ +enum bfi_dport_req { + BFI_DPORT_DISABLE = 0, /* disable dport request */ + BFI_DPORT_ENABLE = 1, /* enable dport request */ +}; + +struct bfi_diag_dport_req_s { + struct bfi_mhdr_s mh; /* 4 bytes */ + u8 req; /* request 1: enable 0: disable */ + u8 status; /* reply status */ + u8 rsvd[2]; + u32 msgtag; /* msgtag for reply */ +}; +#define bfi_diag_dport_rsp_t struct bfi_diag_dport_req_s + +/* * PHY module specific */ enum bfi_phy_h2i_msgs_e { @@ -1147,6 +1171,50 @@ struct bfi_phy_write_rsp_s { u32 length; }; +enum bfi_fru_h2i_msgs { + BFI_FRUVPD_H2I_WRITE_REQ = 1, + BFI_FRUVPD_H2I_READ_REQ = 2, + BFI_TFRU_H2I_WRITE_REQ = 3, + BFI_TFRU_H2I_READ_REQ = 4, +}; + +enum bfi_fru_i2h_msgs { + BFI_FRUVPD_I2H_WRITE_RSP = BFA_I2HM(1), + BFI_FRUVPD_I2H_READ_RSP = BFA_I2HM(2), + BFI_TFRU_I2H_WRITE_RSP = BFA_I2HM(3), + BFI_TFRU_I2H_READ_RSP = BFA_I2HM(4), +}; + +/* + * FRU write request + */ +struct bfi_fru_write_req_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u8 last; + u8 rsv[3]; + u32 offset; + u32 length; + struct bfi_alen_s alen; +}; + +/* + * FRU read request + */ +struct bfi_fru_read_req_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u32 offset; + u32 length; + struct bfi_alen_s alen; +}; + +/* + * FRU response + */ +struct bfi_fru_rsp_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u32 status; + u32 length; +}; #pragma pack() #endif /* __BFI_H__ */ diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h index d4220e13cafa..5ae2c167b2c8 100644 --- a/drivers/scsi/bfa/bfi_ms.h +++ b/drivers/scsi/bfa/bfi_ms.h @@ -426,6 +426,7 @@ struct bfi_lps_login_req_s { u8 auth_en; u8 lps_role; u8 bb_scn; + u32 vvl_flag; }; struct bfi_lps_login_rsp_s { @@ -499,6 +500,9 @@ enum bfi_rport_i2h_msgs { BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1), BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2), BFI_RPORT_I2H_QOS_SCN = BFA_I2HM(3), + BFI_RPORT_I2H_LIP_SCN_ONLINE = BFA_I2HM(4), + BFI_RPORT_I2H_LIP_SCN_OFFLINE = BFA_I2HM(5), + BFI_RPORT_I2H_NO_DEV = BFA_I2HM(6), }; struct bfi_rport_create_req_s { @@ -551,6 +555,14 @@ struct bfi_rport_qos_scn_s { struct bfa_rport_qos_attr_s new_qos_attr; /* New QoS Attributes */ }; +struct bfi_rport_lip_scn_s { + struct bfi_mhdr_s mh; /*!< common msg header */ + u16 bfa_handle; /*!< host rport handle */ + u8 status; /*!< scn online status */ + u8 rsvd; + struct bfa_fcport_loop_info_s loop_info; +}; + union bfi_rport_h2i_msg_u { struct bfi_msg_s *msg; struct bfi_rport_create_req_s *create_req; @@ -563,6 +575,7 @@ union bfi_rport_i2h_msg_u { struct bfi_rport_create_rsp_s *create_rsp; struct bfi_rport_delete_rsp_s *delete_rsp; struct bfi_rport_qos_scn_s *qos_scn_evt; + struct bfi_rport_lip_scn_s *lip_scn; }; /* @@ -828,6 +841,7 @@ enum bfi_tskim_status { */ BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */ BFI_TSKIM_STS_ABORTED = 11, /* Aborted on host request */ + BFI_TSKIM_STS_UTAG = 12, /* unknown tag for request */ }; struct bfi_tskim_rsp_s { diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h index ed5f159e1867..99133bcf53f9 100644 --- a/drivers/scsi/bfa/bfi_reg.h +++ b/drivers/scsi/bfa/bfi_reg.h @@ -338,6 +338,7 @@ enum { #define __A2T_AHB_LOAD 0x00000800 #define __WGN_READY 0x00000400 #define __GLBL_PF_VF_CFG_RDY 0x00000200 +#define CT2_NFC_STS_REG 0x00027410 #define CT2_NFC_CSR_CLR_REG 0x00027420 #define CT2_NFC_CSR_SET_REG 0x00027424 #define __HALT_NFC_CONTROLLER 0x00000002 @@ -355,6 +356,8 @@ enum { (CT2_CSI_MAC0_CONTROL_REG + \ (__n) * (CT2_CSI_MAC1_CONTROL_REG - CT2_CSI_MAC0_CONTROL_REG)) +#define CT2_NFC_FLASH_STS_REG 0x00014834 +#define __FLASH_PLL_INIT_AND_RESET_IN_PROGRESS 0x00000020 /* * Name semaphore registers based on usage */ diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 078d262ac7cc..666b7ac4475f 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1643,7 +1643,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); - skb->priority = port->priority; + skb->priority = fcoe->priority; if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && fcoe->realdev->features & NETIF_F_HW_VLAN_TX) { @@ -1917,7 +1917,6 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier, struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct net_device *netdev; - struct fcoe_port *port; int prio; if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) @@ -1946,10 +1945,8 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier, entry->app.protocol == ETH_P_FCOE) ctlr->priority = prio; - if (entry->app.protocol == ETH_P_FCOE) { - port = lport_priv(ctlr->lp); - port->priority = prio; - } + if (entry->app.protocol == ETH_P_FCOE) + fcoe->priority = prio; return NOTIFY_OK; } @@ -2180,7 +2177,6 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) 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 dcb_app app = { .priority = 0, .protocol = ETH_P_FCOE @@ -2202,8 +2198,8 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) fup = dcb_getapp(netdev, &app); } - port->priority = ffs(up) ? ffs(up) - 1 : 0; - ctlr->priority = ffs(fup) ? ffs(fup) - 1 : port->priority; + fcoe->priority = ffs(up) ? ffs(up) - 1 : 0; + ctlr->priority = ffs(fup) ? ffs(fup) - 1 : fcoe->priority; } #endif } diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index a624add4f8ec..b42dc32cb5eb 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -71,6 +71,7 @@ do { \ * @oem: The offload exchange manager for all local port * instances associated with this port * @removed: Indicates fcoe interface removed from net device + * @priority: Priority for the FCoE packet (DCB) * This structure is 1:1 with a net device. */ struct fcoe_interface { @@ -81,6 +82,7 @@ struct fcoe_interface { struct packet_type fip_packet_type; struct fc_exch_mgr *oem; u8 removed; + u8 priority; }; #define fcoe_to_ctlr(x) \ diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 14243fa5f8e8..fcb9d0b20ee4 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -851,7 +851,8 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) fc_rp_info = (struct fcp_resp_rsp_info *)(rp_ex + 1); if (flags & FCP_RSP_LEN_VAL) { respl = ntohl(rp_ex->fr_rsp_len); - if (respl != sizeof(*fc_rp_info)) + if ((respl != FCP_RESP_RSP_INFO_LEN4) && + (respl != FCP_RESP_RSP_INFO_LEN8)) goto len_err; if (fsp->wait_for_comp) { /* Abuse cdb_status for rsp code */ diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a184c2443a64..69b59935b53f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -27,6 +27,8 @@ struct lpfc_sli2_slim; +#define ELX_MODEL_NAME_SIZE 80 + #define LPFC_PCI_DEV_LP 0x1 #define LPFC_PCI_DEV_OC 0x2 diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b032562aa0d9..ad16e54ac383 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3935,6 +3935,12 @@ MODULE_PARM_DESC(lpfc_fcp_look_ahead, "Look ahead for completions"); # - Only meaningful if BG is turned on (lpfc_enable_bg=1). # - Allows you to ultimately specify which profiles to use # - Default will result in registering capabilities for all profiles. +# - SHOST_DIF_TYPE1_PROTECTION 1 +# HBA supports T10 DIF Type 1: HBA to Target Type 1 Protection +# - SHOST_DIX_TYPE0_PROTECTION 8 +# HBA supports DIX Type 0: Host to HBA protection only +# - SHOST_DIX_TYPE1_PROTECTION 16 +# HBA supports DIX Type 1: Host to HBA Type 1 protection # */ unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION | @@ -3947,7 +3953,7 @@ MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask"); /* # lpfc_prot_guard: i # - Bit mask of protection guard types to register with the SCSI mid-layer -# - Guard types are currently either 1) IP checksum 2) T10-DIF CRC +# - Guard types are currently either 1) T10-DIF CRC 2) IP checksum # - Allows you to ultimately specify which profiles to use # - Default will result in registering capabilities for all guard types # diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index e470c489de07..4380a44000bc 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -467,3 +467,4 @@ int lpfc_sli4_read_config(struct lpfc_hba *); void lpfc_sli4_node_prep(struct lpfc_hba *); int lpfc_sli4_xri_sgl_update(struct lpfc_hba *); void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *); +uint32_t lpfc_sli_port_speed_get(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index cfe533bc9790..f19e9b6f9f13 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -809,6 +809,8 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->fc_ratov = FF_DEF_RATOV; rc = memcmp(&vport->fc_portname, &sp->portName, sizeof(vport->fc_portname)); + memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); + if (rc >= 0) { /* This side will initiate the PLOGI */ spin_lock_irq(shost->host_lock); @@ -3160,7 +3162,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 1; break; } - if (cmd == ELS_CMD_PLOGI) { + if ((cmd == ELS_CMD_PLOGI) || + (cmd == ELS_CMD_PRLI)) { delay = 1000; maxretry = lpfc_max_els_tries + 1; retry = 1; @@ -3305,7 +3308,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_prev_state = ndlp->nlp_state; if (cmd == ELS_CMD_PRLI) lpfc_nlp_set_state(vport, ndlp, - NLP_STE_REG_LOGIN_ISSUE); + NLP_STE_PRLI_ISSUE); else lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e9845d2ecf10..d7096ad94d3f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1506,9 +1506,10 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, } } - /* If FCF not available return 0 */ + /* FCF not valid/available or solicitation in progress */ if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || - !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record)) + !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record) || + bf_get(lpfc_fcf_record_fcf_sol, new_fcf_record)) return 0; if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { @@ -1842,6 +1843,7 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, "\tFCF_Index : x%x\n" "\tFCF_Avail : x%x\n" "\tFCF_Valid : x%x\n" + "\tFCF_SOL : x%x\n" "\tFIP_Priority : x%x\n" "\tMAC_Provider : x%x\n" "\tLowest VLANID : x%x\n" @@ -1852,6 +1854,7 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, bf_get(lpfc_fcf_record_fcf_index, fcf_record), bf_get(lpfc_fcf_record_fcf_avail, fcf_record), bf_get(lpfc_fcf_record_fcf_valid, fcf_record), + bf_get(lpfc_fcf_record_fcf_sol, fcf_record), fcf_record->fip_priority, bf_get(lpfc_fcf_record_mac_addr_prov, fcf_record), vlan_id, @@ -2185,12 +2188,14 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) new_fcf_record)); lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, "2781 FCF (x%x) failed connection " - "list check: (x%x/x%x)\n", + "list check: (x%x/x%x/%x)\n", bf_get(lpfc_fcf_record_fcf_index, new_fcf_record), bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record), bf_get(lpfc_fcf_record_fcf_valid, + new_fcf_record), + bf_get(lpfc_fcf_record_fcf_sol, new_fcf_record)); if ((phba->fcf.fcf_flag & FCF_IN_USE) && lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 834b699cac76..2cdeb5434fb7 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1305,6 +1305,11 @@ struct lpfc_mbx_mq_create_ext { #define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK #define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001 #define lpfc_mbx_mq_create_ext_async_evt_link_WORD async_evt_bmap +#define LPFC_EVT_CODE_LINK_NO_LINK 0x0 +#define LPFC_EVT_CODE_LINK_10_MBIT 0x1 +#define LPFC_EVT_CODE_LINK_100_MBIT 0x2 +#define LPFC_EVT_CODE_LINK_1_GBIT 0x3 +#define LPFC_EVT_CODE_LINK_10_GBIT 0x4 #define lpfc_mbx_mq_create_ext_async_evt_fip_SHIFT LPFC_TRAILER_CODE_FCOE #define lpfc_mbx_mq_create_ext_async_evt_fip_MASK 0x00000001 #define lpfc_mbx_mq_create_ext_async_evt_fip_WORD async_evt_bmap @@ -1314,6 +1319,13 @@ struct lpfc_mbx_mq_create_ext { #define lpfc_mbx_mq_create_ext_async_evt_fc_SHIFT LPFC_TRAILER_CODE_FC #define lpfc_mbx_mq_create_ext_async_evt_fc_MASK 0x00000001 #define lpfc_mbx_mq_create_ext_async_evt_fc_WORD async_evt_bmap +#define LPFC_EVT_CODE_FC_NO_LINK 0x0 +#define LPFC_EVT_CODE_FC_1_GBAUD 0x1 +#define LPFC_EVT_CODE_FC_2_GBAUD 0x2 +#define LPFC_EVT_CODE_FC_4_GBAUD 0x4 +#define LPFC_EVT_CODE_FC_8_GBAUD 0x8 +#define LPFC_EVT_CODE_FC_10_GBAUD 0xA +#define LPFC_EVT_CODE_FC_16_GBAUD 0x10 #define lpfc_mbx_mq_create_ext_async_evt_sli_SHIFT LPFC_TRAILER_CODE_SLI #define lpfc_mbx_mq_create_ext_async_evt_sli_MASK 0x00000001 #define lpfc_mbx_mq_create_ext_async_evt_sli_WORD async_evt_bmap @@ -1695,8 +1707,14 @@ struct fcf_record { #define lpfc_fcf_record_fc_map_2_MASK 0x000000FF #define lpfc_fcf_record_fc_map_2_WORD word7 #define lpfc_fcf_record_fcf_valid_SHIFT 24 -#define lpfc_fcf_record_fcf_valid_MASK 0x000000FF +#define lpfc_fcf_record_fcf_valid_MASK 0x00000001 #define lpfc_fcf_record_fcf_valid_WORD word7 +#define lpfc_fcf_record_fcf_fc_SHIFT 25 +#define lpfc_fcf_record_fcf_fc_MASK 0x00000001 +#define lpfc_fcf_record_fcf_fc_WORD word7 +#define lpfc_fcf_record_fcf_sol_SHIFT 31 +#define lpfc_fcf_record_fcf_sol_MASK 0x00000001 +#define lpfc_fcf_record_fcf_sol_WORD word7 uint32_t word8; #define lpfc_fcf_record_fcf_index_SHIFT 0 #define lpfc_fcf_record_fcf_index_MASK 0x0000FFFF diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 8a55a586dd65..7dc4218d9c4c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1892,8 +1892,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) max_speed = 4; else if (phba->lmt & LMT_2Gb) max_speed = 2; - else + else if (phba->lmt & LMT_1Gb) max_speed = 1; + else + max_speed = 0; vp = &phba->vpd; @@ -2078,9 +2080,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) if (descp && descp[0] == '\0') { if (oneConnect) snprintf(descp, 255, - "Emulex OneConnect %s, %s Initiator, Port %s", + "Emulex OneConnect %s, %s Initiator %s", m.name, m.function, phba->Port); + else if (max_speed == 0) + snprintf(descp, 255, + "Emulex %s %s %s ", + m.name, m.bus, m.function); else snprintf(descp, 255, "Emulex %s %d%s %s %s", @@ -3502,6 +3508,119 @@ lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba, } /** + * lpfc_sli_port_speed_get - Get sli3 link speed code to link speed + * @phba: pointer to lpfc hba data structure. + * + * This routine is to get an SLI3 FC port's link speed in Mbps. + * + * Return: link speed in terms of Mbps. + **/ +uint32_t +lpfc_sli_port_speed_get(struct lpfc_hba *phba) +{ + uint32_t link_speed; + + if (!lpfc_is_link_up(phba)) + return 0; + + switch (phba->fc_linkspeed) { + case LPFC_LINK_SPEED_1GHZ: + link_speed = 1000; + break; + case LPFC_LINK_SPEED_2GHZ: + link_speed = 2000; + break; + case LPFC_LINK_SPEED_4GHZ: + link_speed = 4000; + break; + case LPFC_LINK_SPEED_8GHZ: + link_speed = 8000; + break; + case LPFC_LINK_SPEED_10GHZ: + link_speed = 10000; + break; + case LPFC_LINK_SPEED_16GHZ: + link_speed = 16000; + break; + default: + link_speed = 0; + } + return link_speed; +} + +/** + * lpfc_sli4_port_speed_parse - Parse async evt link speed code to link speed + * @phba: pointer to lpfc hba data structure. + * @evt_code: asynchronous event code. + * @speed_code: asynchronous event link speed code. + * + * This routine is to parse the giving SLI4 async event link speed code into + * value of Mbps for the link speed. + * + * Return: link speed in terms of Mbps. + **/ +static uint32_t +lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, + uint8_t speed_code) +{ + uint32_t port_speed; + + switch (evt_code) { + case LPFC_TRAILER_CODE_LINK: + switch (speed_code) { + case LPFC_EVT_CODE_LINK_NO_LINK: + port_speed = 0; + break; + case LPFC_EVT_CODE_LINK_10_MBIT: + port_speed = 10; + break; + case LPFC_EVT_CODE_LINK_100_MBIT: + port_speed = 100; + break; + case LPFC_EVT_CODE_LINK_1_GBIT: + port_speed = 1000; + break; + case LPFC_EVT_CODE_LINK_10_GBIT: + port_speed = 10000; + break; + default: + port_speed = 0; + } + break; + case LPFC_TRAILER_CODE_FC: + switch (speed_code) { + case LPFC_EVT_CODE_FC_NO_LINK: + port_speed = 0; + break; + case LPFC_EVT_CODE_FC_1_GBAUD: + port_speed = 1000; + break; + case LPFC_EVT_CODE_FC_2_GBAUD: + port_speed = 2000; + break; + case LPFC_EVT_CODE_FC_4_GBAUD: + port_speed = 4000; + break; + case LPFC_EVT_CODE_FC_8_GBAUD: + port_speed = 8000; + break; + case LPFC_EVT_CODE_FC_10_GBAUD: + port_speed = 10000; + break; + case LPFC_EVT_CODE_FC_16_GBAUD: + port_speed = 16000; + break; + default: + port_speed = 0; + } + break; + default: + port_speed = 0; + } + return port_speed; +} + +/** * lpfc_sli4_async_link_evt - Process the asynchronous FCoE link event * @phba: pointer to lpfc hba data structure. * @acqe_link: pointer to the async link completion queue entry. @@ -3558,7 +3677,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, /* Keep the link status for extra SLI4 state machine reference */ phba->sli4_hba.link_state.speed = - bf_get(lpfc_acqe_link_speed, acqe_link); + lpfc_sli4_port_speed_parse(phba, LPFC_TRAILER_CODE_LINK, + bf_get(lpfc_acqe_link_speed, acqe_link)); phba->sli4_hba.link_state.duplex = bf_get(lpfc_acqe_link_duplex, acqe_link); phba->sli4_hba.link_state.status = @@ -3570,7 +3690,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->sli4_hba.link_state.fault = bf_get(lpfc_acqe_link_fault, acqe_link); phba->sli4_hba.link_state.logical_speed = - bf_get(lpfc_acqe_logical_link_speed, acqe_link); + bf_get(lpfc_acqe_logical_link_speed, acqe_link) * 10; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2900 Async FC/FCoE Link event - Speed:%dGBit " "duplex:x%x LA Type:x%x Port Type:%d Port Number:%d " @@ -3580,7 +3701,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->sli4_hba.link_state.status, phba->sli4_hba.link_state.type, phba->sli4_hba.link_state.number, - phba->sli4_hba.link_state.logical_speed * 10, + phba->sli4_hba.link_state.logical_speed, phba->sli4_hba.link_state.fault); /* * For FC Mode: issue the READ_TOPOLOGY mailbox command to fetch @@ -3652,7 +3773,8 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) } /* Keep the link status for extra SLI4 state machine reference */ phba->sli4_hba.link_state.speed = - bf_get(lpfc_acqe_fc_la_speed, acqe_fc); + lpfc_sli4_port_speed_parse(phba, LPFC_TRAILER_CODE_FC, + bf_get(lpfc_acqe_fc_la_speed, acqe_fc)); phba->sli4_hba.link_state.duplex = LPFC_ASYNC_LINK_DUPLEX_FULL; phba->sli4_hba.link_state.topology = bf_get(lpfc_acqe_fc_la_topology, acqe_fc); @@ -3665,7 +3787,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) phba->sli4_hba.link_state.fault = bf_get(lpfc_acqe_link_fault, acqe_fc); phba->sli4_hba.link_state.logical_speed = - bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc); + bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10; lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2896 Async FC event - Speed:%dGBaud Topology:x%x " "LA Type:x%x Port Type:%d Port Number:%d Logical speed:" @@ -3675,7 +3797,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) phba->sli4_hba.link_state.status, phba->sli4_hba.link_state.type, phba->sli4_hba.link_state.number, - phba->sli4_hba.link_state.logical_speed * 10, + phba->sli4_hba.link_state.logical_speed, phba->sli4_hba.link_state.fault); pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { @@ -3783,14 +3905,18 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) case LPFC_SLI_EVENT_STATUS_VALID: return; /* no message if the sfp is okay */ case LPFC_SLI_EVENT_STATUS_NOT_PRESENT: - sprintf(message, "Not installed"); + sprintf(message, "Optics faulted/incorrectly installed/not " \ + "installed - Reseat optics, if issue not " + "resolved, replace."); break; case LPFC_SLI_EVENT_STATUS_WRONG_TYPE: sprintf(message, - "Optics of two types installed"); + "Optics of two types installed - Remove one optic or " \ + "install matching pair of optics."); break; case LPFC_SLI_EVENT_STATUS_UNSUPPORTED: - sprintf(message, "Incompatible optics"); + sprintf(message, "Incompatible optics - Replace with " \ + "compatible optics for card to function."); break; default: /* firmware is reporting a status we don't know about */ @@ -4161,11 +4287,11 @@ lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, phba->fcoe_eventtag = acqe_grp5->event_tag; prev_ll_spd = phba->sli4_hba.link_state.logical_speed; phba->sli4_hba.link_state.logical_speed = - (bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5)); + (bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5)) * 10; lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2789 GRP5 Async Event: Updating logical link speed " - "from %dMbps to %dMbps\n", (prev_ll_spd * 10), - (phba->sli4_hba.link_state.logical_speed*10)); + "from %dMbps to %dMbps\n", prev_ll_spd, + phba->sli4_hba.link_state.logical_speed); } /** @@ -4947,7 +5073,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) } phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) * - phba->sli4_hba.cfg_eqn), GFP_KERNEL); + phba->cfg_fcp_io_channel), GFP_KERNEL); if (!phba->sli4_hba.msix_entries) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2573 Failed allocate memory for msi-x " @@ -6559,7 +6685,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) i++; } if (i < cfg_fcp_io_channel) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + lpfc_printf_log(phba, + KERN_ERR, LOG_INIT, "3188 Reducing IO channels to match number of " "CPUs: from %d to %d\n", cfg_fcp_io_channel, i); cfg_fcp_io_channel = i; @@ -6567,8 +6694,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) if (cfg_fcp_io_channel > phba->sli4_hba.max_cfg_param.max_eq) { - cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq; - if (cfg_fcp_io_channel < LPFC_FCP_IO_CHAN_MIN) { + if (phba->sli4_hba.max_cfg_param.max_eq < + LPFC_FCP_IO_CHAN_MIN) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2574 Not enough EQs (%d) from the " "pci function for supporting FCP " @@ -6577,13 +6704,12 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) phba->cfg_fcp_io_channel); goto out_error; } - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2575 Not enough EQs (%d) from the pci " - "function for supporting the requested " - "FCP EQs (%d), the actual FCP EQs can " - "be supported: %d\n", - phba->sli4_hba.max_cfg_param.max_eq, - phba->cfg_fcp_io_channel, cfg_fcp_io_channel); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2575 Reducing IO channels to match number of " + "available EQs: from %d to %d\n", + cfg_fcp_io_channel, + phba->sli4_hba.max_cfg_param.max_eq); + cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq; } /* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */ @@ -6592,7 +6718,6 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) phba->cfg_fcp_eq_count = cfg_fcp_io_channel; phba->cfg_fcp_wq_count = cfg_fcp_io_channel; phba->cfg_fcp_io_channel = cfg_fcp_io_channel; - phba->sli4_hba.cfg_eqn = cfg_fcp_io_channel; /* Get EQ depth from module parameter, fake the default for now */ phba->sli4_hba.eq_esize = LPFC_EQE_SIZE_4B; @@ -8095,11 +8220,11 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) int vectors, rc, index; /* Set up MSI-X multi-message vectors */ - for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) + for (index = 0; index < phba->cfg_fcp_io_channel; index++) phba->sli4_hba.msix_entries[index].entry = index; /* Configure MSI-X capability structure */ - vectors = phba->sli4_hba.cfg_eqn; + vectors = phba->cfg_fcp_io_channel; enable_msix_vectors: rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, vectors); @@ -8142,8 +8267,14 @@ enable_msix_vectors: goto cfg_fail_out; } } - phba->sli4_hba.msix_vec_nr = vectors; + if (vectors != phba->cfg_fcp_io_channel) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3238 Reducing IO channels to match number of " + "MSI-X vectors, requested %d got %d\n", + phba->cfg_fcp_io_channel, vectors); + phba->cfg_fcp_io_channel = vectors; + } return rc; cfg_fail_out: @@ -8171,7 +8302,7 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba) int index; /* Free up MSI-X multi-message vectors */ - for (index = 0; index < phba->sli4_hba.msix_vec_nr; index++) + for (index = 0; index < phba->cfg_fcp_io_channel; index++) free_irq(phba->sli4_hba.msix_entries[index].vector, &phba->sli4_hba.fcp_eq_hdl[index]); @@ -9304,23 +9435,28 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) /** * lpfc_write_firmware - attempt to write a firmware image to the port - * @phba: pointer to lpfc hba data structure. * @fw: pointer to firmware image returned from request_firmware. + * @phba: pointer to lpfc hba data structure. * - * returns the number of bytes written if write is successful. - * returns a negative error value if there were errors. - * returns 0 if firmware matches currently active firmware on port. **/ -int -lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) +static void +lpfc_write_firmware(const struct firmware *fw, void *context) { + struct lpfc_hba *phba = (struct lpfc_hba *)context; char fwrev[FW_REV_STR_SIZE]; - struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data; + struct lpfc_grp_hdr *image; struct list_head dma_buffer_list; int i, rc = 0; struct lpfc_dmabuf *dmabuf, *next; uint32_t offset = 0, temp_offset = 0; + /* It can be null, sanity check */ + if (!fw) { + rc = -ENXIO; + goto out; + } + image = (struct lpfc_grp_hdr *)fw->data; + INIT_LIST_HEAD(&dma_buffer_list); if ((be32_to_cpu(image->magic_number) != LPFC_GROUP_OJECT_MAGIC_NUM) || (bf_get_be32(lpfc_grp_hdr_file_type, image) != @@ -9333,12 +9469,13 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) be32_to_cpu(image->magic_number), bf_get_be32(lpfc_grp_hdr_file_type, image), bf_get_be32(lpfc_grp_hdr_id, image)); - return -EINVAL; + rc = -EINVAL; + goto release_out; } lpfc_decode_firmware_rev(phba, fwrev, 1); if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3023 Updating Firmware. Current Version:%s " + "3023 Updating Firmware, Current Version:%s " "New Version:%s\n", fwrev, image->revision); for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) { @@ -9346,7 +9483,7 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) GFP_KERNEL); if (!dmabuf) { rc = -ENOMEM; - goto out; + goto release_out; } dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, @@ -9355,7 +9492,7 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) if (!dmabuf->virt) { kfree(dmabuf); rc = -ENOMEM; - goto out; + goto release_out; } list_add_tail(&dmabuf->list, &dma_buffer_list); } @@ -9375,23 +9512,24 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) } rc = lpfc_wr_object(phba, &dma_buffer_list, (fw->size - offset), &offset); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3024 Firmware update failed. " - "%d\n", rc); - goto out; - } + if (rc) + goto release_out; } rc = offset; } -out: + +release_out: list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) { list_del(&dmabuf->list); dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, dmabuf->virt, dmabuf->phys); kfree(dmabuf); } - return rc; + release_firmware(fw); +out: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3024 Firmware update done: %d.", rc); + return; } /** @@ -9418,12 +9556,11 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) struct lpfc_hba *phba; struct lpfc_vport *vport = NULL; struct Scsi_Host *shost = NULL; - int error; + int error, ret; uint32_t cfg_mode, intr_mode; int mcnt; int adjusted_fcp_io_channel; - const struct firmware *fw; - uint8_t file_name[16]; + uint8_t file_name[ELX_MODEL_NAME_SIZE]; /* Allocate memory for HBA structure */ phba = lpfc_hba_alloc(pdev); @@ -9525,9 +9662,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Default to single EQ for non-MSI-X */ if (phba->intr_type != MSIX) adjusted_fcp_io_channel = 1; - else if (phba->sli4_hba.msix_vec_nr < - phba->cfg_fcp_io_channel) - adjusted_fcp_io_channel = phba->sli4_hba.msix_vec_nr; else adjusted_fcp_io_channel = phba->cfg_fcp_io_channel; phba->cfg_fcp_io_channel = adjusted_fcp_io_channel; @@ -9572,12 +9706,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* check for firmware upgrade or downgrade (if_type 2 only) */ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_IF_TYPE_2) { - snprintf(file_name, 16, "%s.grp", phba->ModelName); - error = request_firmware(&fw, file_name, &phba->pcidev->dev); - if (!error) { - lpfc_write_firmware(phba, fw); - release_firmware(fw); - } + snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", + phba->ModelName); + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + file_name, &phba->pcidev->dev, + GFP_KERNEL, (void *)phba, + lpfc_write_firmware); } /* Check if there are static vports to be created. */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 64013f3097ad..7f45ac9964a9 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3829,9 +3829,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, flags); lpfc_cmd->pCmd = NULL; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); /* * If there is a thread waiting for command completion @@ -3871,9 +3871,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } } - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, flags); lpfc_cmd->pCmd = NULL; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); /* * If there is a thread waiting for command completion @@ -4163,7 +4163,7 @@ lpfc_info(struct Scsi_Host *host) { struct lpfc_vport *vport = (struct lpfc_vport *) host->hostdata; struct lpfc_hba *phba = vport->phba; - int len; + int len, link_speed = 0; static char lpfcinfobuf[384]; memset(lpfcinfobuf,0,384); @@ -4184,12 +4184,18 @@ lpfc_info(struct Scsi_Host *host) phba->Port); } len = strlen(lpfcinfobuf); - if (phba->sli4_hba.link_state.logical_speed) { - snprintf(lpfcinfobuf + len, - 384-len, - " Logical Link Speed: %d Mbps", - phba->sli4_hba.link_state.logical_speed * 10); + if (phba->sli_rev <= LPFC_SLI_REV3) { + link_speed = lpfc_sli_port_speed_get(phba); + } else { + if (phba->sli4_hba.link_state.logical_speed) + link_speed = + phba->sli4_hba.link_state.logical_speed; + else + link_speed = phba->sli4_hba.link_state.speed; } + if (link_speed != 0) + snprintf(lpfcinfobuf + len, 384-len, + " Logical Link Speed: %d Mbps", link_speed); } return lpfcinfobuf; } @@ -4398,16 +4404,17 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) struct lpfc_scsi_buf *lpfc_cmd; IOCB_t *cmd, *icmd; int ret = SUCCESS, status = 0; + unsigned long flags; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); status = fc_block_scsi_eh(cmnd); if (status != 0 && status != SUCCESS) return status; - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, flags); /* driver queued commands are in process of being flushed */ if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "3168 SCSI Layer abort requested I/O has been " "flushed by LLD.\n"); @@ -4416,7 +4423,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; if (!lpfc_cmd || !lpfc_cmd->pCmd) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " "x%x ID %d LUN %d\n", @@ -4427,7 +4434,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) iocb = &lpfc_cmd->cur_iocbq; /* the command is in process of being cancelled */ if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "3169 SCSI Layer abort requested I/O has been " "cancelled by LLD.\n"); @@ -4484,7 +4491,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; abtsiocb->vport = vport; /* no longer need the lock after this point */ - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == IOCB_ERROR) { @@ -4516,7 +4523,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) goto out; out_unlock: - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0749 SCSI Layer I/O Abort Request Status x%x ID %d " diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 219bf534ef99..d7f3313ef886 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3964,9 +3964,9 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - /* Perform FCoE PCI function reset */ - lpfc_sli4_queue_destroy(phba); + /* Perform FCoE PCI function reset before freeing queue memory */ rc = lpfc_pci_function_reset(phba); + lpfc_sli4_queue_destroy(phba); /* Restore PCI cmd register */ pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); @@ -7072,6 +7072,40 @@ lpfc_sli4_async_mbox_unblock(struct lpfc_hba *phba) } /** + * lpfc_sli4_wait_bmbx_ready - Wait for bootstrap mailbox register ready + * @phba: Pointer to HBA context object. + * @mboxq: Pointer to mailbox object. + * + * The function waits for the bootstrap mailbox register ready bit from + * port for twice the regular mailbox command timeout value. + * + * 0 - no timeout on waiting for bootstrap mailbox register ready. + * MBXERR_ERROR - wait for bootstrap mailbox register timed out. + **/ +static int +lpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + uint32_t db_ready; + unsigned long timeout; + struct lpfc_register bmbx_reg; + + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) + * 1000) + jiffies; + + do { + bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); + db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); + if (!db_ready) + msleep(2); + + if (time_after(jiffies, timeout)) + return MBXERR_ERROR; + } while (!db_ready); + + return 0; +} + +/** * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox * @phba: Pointer to HBA context object. * @mboxq: Pointer to mailbox object. @@ -7092,15 +7126,12 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { int rc = MBX_SUCCESS; unsigned long iflag; - uint32_t db_ready; uint32_t mcqe_status; uint32_t mbx_cmnd; - unsigned long timeout; struct lpfc_sli *psli = &phba->sli; struct lpfc_mqe *mb = &mboxq->u.mqe; struct lpfc_bmbx_create *mbox_rgn; struct dma_address *dma_address; - struct lpfc_register bmbx_reg; /* * Only one mailbox can be active to the bootstrap mailbox region @@ -7124,6 +7155,11 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->sli.mbox_active = mboxq; spin_unlock_irqrestore(&phba->hbalock, iflag); + /* wait for bootstrap mbox register for readyness */ + rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); + if (rc) + goto exit; + /* * Initialize the bootstrap memory region to avoid stale data areas * in the mailbox post. Then copy the caller's mailbox contents to @@ -7138,35 +7174,18 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) dma_address = &phba->sli4_hba.bmbx.dma_address; writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr); - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; - do { - bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); - db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); - if (!db_ready) - msleep(2); - - if (time_after(jiffies, timeout)) { - rc = MBXERR_ERROR; - goto exit; - } - } while (!db_ready); + /* wait for bootstrap mbox register for hi-address write done */ + rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); + if (rc) + goto exit; /* Post the low mailbox dma address to the port. */ writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr); - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; - do { - bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); - db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); - if (!db_ready) - msleep(2); - if (time_after(jiffies, timeout)) { - rc = MBXERR_ERROR; - goto exit; - } - } while (!db_ready); + /* wait for bootstrap mbox register for low address write done */ + rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); + if (rc) + goto exit; /* * Read the CQ to ensure the mailbox has completed. @@ -8090,6 +8109,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com, + iocbq->iocb.ulpFCP2Rcvy); break; case CMD_GEN_REQUEST64_CR: /* For this command calculate the xmit length of the @@ -12099,6 +12120,7 @@ lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) struct lpfc_queue *eq; int cnt, rc, length, status = 0; uint32_t shdr_status, shdr_add_status; + uint32_t result; int fcp_eqidx; union lpfc_sli4_cfg_shdr *shdr; uint16_t dmult; @@ -12117,8 +12139,11 @@ lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) eq_delay = &mbox->u.mqe.un.eq_delay; /* Calculate delay multiper from maximum interrupt per second */ - dmult = phba->cfg_fcp_imax / phba->cfg_fcp_io_channel; - dmult = LPFC_DMULT_CONST/dmult - 1; + result = phba->cfg_fcp_imax / phba->cfg_fcp_io_channel; + if (result > LPFC_DMULT_CONST) + dmult = 0; + else + dmult = LPFC_DMULT_CONST/result - 1; cnt = 0; for (fcp_eqidx = startq; fcp_eqidx < phba->cfg_fcp_io_channel; @@ -12174,7 +12199,7 @@ lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) * fails this function will return -ENXIO. **/ uint32_t -lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) +lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) { struct lpfc_mbx_eq_create *eq_create; LPFC_MBOXQ_t *mbox; @@ -12206,7 +12231,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) LPFC_EQE_SIZE); bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1); /* Calculate delay multiper from maximum interrupt per second */ - dmult = LPFC_DMULT_CONST/imax - 1; + if (imax > LPFC_DMULT_CONST) + dmult = 0; + else + dmult = LPFC_DMULT_CONST/imax - 1; bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context, dmult); switch (eq->entry_count) { diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index bd4bc4342ae2..f44a06a4c6e7 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -37,7 +37,7 @@ /* Multi-queue arrangement for FCP EQ/CQ/WQ tuples */ #define LPFC_FCP_IO_CHAN_DEF 4 #define LPFC_FCP_IO_CHAN_MIN 1 -#define LPFC_FCP_IO_CHAN_MAX 8 +#define LPFC_FCP_IO_CHAN_MAX 16 /* * Provide the default FCF Record attributes used by the driver @@ -168,7 +168,7 @@ struct lpfc_queue { }; struct lpfc_sli4_link { - uint8_t speed; + uint16_t speed; uint8_t duplex; uint8_t status; uint8_t type; @@ -490,8 +490,6 @@ struct lpfc_sli4_hba { struct lpfc_pc_sli4_params pc_sli4_params; struct msix_entry *msix_entries; uint8_t handler_name[LPFC_FCP_IO_CHAN_MAX][LPFC_SLI4_HANDLER_NAME_SZ]; - uint32_t cfg_eqn; - uint32_t msix_vec_nr; struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ /* Pointers to the constructed SLI4 queues */ @@ -626,7 +624,7 @@ void lpfc_sli4_hba_reset(struct lpfc_hba *); struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, uint32_t); void lpfc_sli4_queue_free(struct lpfc_queue *); -uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t); +uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint32_t); uint32_t lpfc_modify_fcp_eq_delay(struct lpfc_hba *, uint16_t); uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_queue *, uint32_t, uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 04265a1c4e52..0c2149189dda 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.34" +#define LPFC_DRIVER_VERSION "8.3.35" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index fcb005fa4bd1..16b7a72a70c4 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1,7 +1,7 @@ /* * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2009-2011 LSI Corporation. + * Copyright (c) 2003-2012 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,9 +33,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.06.18-rc1" -#define MEGASAS_RELDATE "Jun. 17, 2012" -#define MEGASAS_EXT_VERSION "Tue. Jun. 17 17:00:00 PDT 2012" +#define MEGASAS_VERSION "06.504.01.00-rc1" +#define MEGASAS_RELDATE "Oct. 1, 2012" +#define MEGASAS_EXT_VERSION "Mon. Oct. 1 17:00:00 PDT 2012" /* * Device IDs diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 0393ec478cdf..d2c5366aff7f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1,7 +1,7 @@ /* * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2009-2011 LSI Corporation. + * Copyright (c) 2003-2012 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * FILE: megaraid_sas_base.c - * Version : v00.00.06.18-rc1 + * Version : v06.504.01.00-rc1 * * Authors: LSI Corporation * Sreenivas Bagalkote @@ -71,6 +71,10 @@ static int msix_disable; module_param(msix_disable, int, S_IRUGO); MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0"); +static unsigned int msix_vectors; +module_param(msix_vectors, int, S_IRUGO); +MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW"); + static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; module_param(throttlequeuedepth, int, S_IRUGO); MODULE_PARM_DESC(throttlequeuedepth, @@ -3520,6 +3524,10 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->msix_vectors = (readl(&instance->reg_set-> outbound_scratch_pad_2 ) & 0x1F) + 1; + if (msix_vectors) + instance->msix_vectors = + min(msix_vectors, + instance->msix_vectors); } else instance->msix_vectors = 1; /* Don't bother allocating more MSI-X vectors than cpus */ @@ -5233,7 +5241,6 @@ megasas_aen_polling(struct work_struct *work) case MR_EVT_PD_REMOVED: if (megasas_get_pd_list(instance) == 0) { - megasas_get_pd_list(instance); for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index e3d251a2e26a..a11df82474ef 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -1,7 +1,7 @@ /* * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2009-2011 LSI Corporation. + * Copyright (c) 2009-2012 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index ddf094e7d0ac..74030aff69ad 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1,7 +1,7 @@ /* * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2009-2011 LSI Corporation. + * Copyright (c) 2009-2012 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1184,8 +1184,6 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, io_request->CDB.EEDP32.PrimaryReferenceTag = cpu_to_be32(ref_tag); io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff; - - io_request->DataLength = num_blocks * 512; io_request->IoFlags = 32; /* Specify 32-byte cdb */ /* Transfer length */ @@ -1329,7 +1327,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, struct megasas_cmd_fusion *cmd) { u8 fp_possible; - u32 start_lba_lo, start_lba_hi, device_id; + u32 start_lba_lo, start_lba_hi, device_id, datalength = 0; struct MPI2_RAID_SCSI_IO_REQUEST *io_request; union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; struct IO_REQUEST_INFO io_info; @@ -1355,7 +1353,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, * 6-byte READ(0x08) or WRITE(0x0A) cdb */ if (scp->cmd_len == 6) { - io_request->DataLength = (u32) scp->cmnd[4]; + datalength = (u32) scp->cmnd[4]; start_lba_lo = ((u32) scp->cmnd[1] << 16) | ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3]; @@ -1366,7 +1364,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, * 10-byte READ(0x28) or WRITE(0x2A) cdb */ else if (scp->cmd_len == 10) { - io_request->DataLength = (u32) scp->cmnd[8] | + datalength = (u32) scp->cmnd[8] | ((u32) scp->cmnd[7] << 8); start_lba_lo = ((u32) scp->cmnd[2] << 24) | ((u32) scp->cmnd[3] << 16) | @@ -1377,7 +1375,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, * 12-byte READ(0xA8) or WRITE(0xAA) cdb */ else if (scp->cmd_len == 12) { - io_request->DataLength = ((u32) scp->cmnd[6] << 24) | + datalength = ((u32) scp->cmnd[6] << 24) | ((u32) scp->cmnd[7] << 16) | ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; start_lba_lo = ((u32) scp->cmnd[2] << 24) | @@ -1389,7 +1387,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, * 16-byte READ(0x88) or WRITE(0x8A) cdb */ else if (scp->cmd_len == 16) { - io_request->DataLength = ((u32) scp->cmnd[10] << 24) | + datalength = ((u32) scp->cmnd[10] << 24) | ((u32) scp->cmnd[11] << 16) | ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13]; start_lba_lo = ((u32) scp->cmnd[6] << 24) | @@ -1403,8 +1401,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo; - io_info.numBlocks = io_request->DataLength; + io_info.numBlocks = datalength; io_info.ldTgtId = device_id; + io_request->DataLength = scsi_bufflen(scp); if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) io_info.isRead = 1; @@ -1431,7 +1430,6 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, if (fp_possible) { megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, local_map_ptr, start_lba_lo); - io_request->DataLength = scsi_bufflen(scp); io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY @@ -1510,7 +1508,8 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, local_map_ptr = fusion->ld_map[(instance->map_id & 1)]; /* Check if this is a system PD I/O */ - if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { + if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS && + instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { io_request->Function = 0; io_request->DevHandle = local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; @@ -1525,6 +1524,8 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + cmd->request_desc->SCSIIO.DevHandle = + local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; } else { io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = device_id; @@ -1732,8 +1733,6 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) return IRQ_NONE; - d_val.word = desc->Words; - num_completed = 0; while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) { @@ -1855,10 +1854,8 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr) } spin_unlock_irqrestore(&instance->hba_lock, flags); - spin_lock_irqsave(&instance->completion_lock, flags); for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) complete_cmd_fusion(instance, MSIxIndex); - spin_unlock_irqrestore(&instance->completion_lock, flags); } /** diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 088c9f91da95..a7c64f051996 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -1,7 +1,7 @@ /* * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2009-2011 LSI Corporation. + * Copyright (c) 2009-2012 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 783edc7c6b98..c585a925b3cd 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -35,10 +35,12 @@ #include <linux/io.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_eh.h> #include <linux/uaccess.h> +#include <linux/kthread.h> #include "mvumi.h" @@ -48,6 +50,7 @@ MODULE_DESCRIPTION("Marvell UMI Driver"); static DEFINE_PCI_DEVICE_TABLE(mvumi_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9143) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9580) }, { 0 } }; @@ -118,7 +121,7 @@ static int mvumi_map_pci_addr(struct pci_dev *dev, void **addr_array) static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, enum resource_type type, unsigned int size) { - struct mvumi_res *res = kzalloc(sizeof(*res), GFP_KERNEL); + struct mvumi_res *res = kzalloc(sizeof(*res), GFP_ATOMIC); if (!res) { dev_err(&mhba->pdev->dev, @@ -128,7 +131,7 @@ static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, switch (type) { case RESOURCE_CACHED_MEMORY: - res->virt_addr = kzalloc(size, GFP_KERNEL); + res->virt_addr = kzalloc(size, GFP_ATOMIC); if (!res->virt_addr) { dev_err(&mhba->pdev->dev, "unable to allocate memory,size = %d.\n", size); @@ -222,11 +225,11 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); m_sg->flags = 0; - m_sg->size = cpu_to_le32(sg_dma_len(&sg[i])); + sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i]))); if ((i + 1) == *sg_count) - m_sg->flags |= SGD_EOT; + m_sg->flags |= 1U << mhba->eot_flag; - m_sg++; + sgd_inc(mhba, m_sg); } } else { scmd->SCp.dma_handle = scsi_bufflen(scmd) ? @@ -237,8 +240,8 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, busaddr = scmd->SCp.dma_handle; m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); - m_sg->flags = SGD_EOT; - m_sg->size = cpu_to_le32(scsi_bufflen(scmd)); + m_sg->flags = 1U << mhba->eot_flag; + sgd_setsz(mhba, m_sg, cpu_to_le32(scsi_bufflen(scmd))); *sg_count = 1; } @@ -267,8 +270,8 @@ static int mvumi_internal_cmd_sgl(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(phy_addr)); m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(phy_addr)); - m_sg->flags = SGD_EOT; - m_sg->size = cpu_to_le32(size); + m_sg->flags = 1U << mhba->eot_flag; + sgd_setsz(mhba, m_sg, cpu_to_le32(size)); return 0; } @@ -285,7 +288,8 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba, } INIT_LIST_HEAD(&cmd->queue_pointer); - cmd->frame = kzalloc(mhba->ib_max_size, GFP_KERNEL); + cmd->frame = pci_alloc_consistent(mhba->pdev, + mhba->ib_max_size, &cmd->frame_phys); if (!cmd->frame) { dev_err(&mhba->pdev->dev, "failed to allocate memory for FW" " frame,size = %d.\n", mhba->ib_max_size); @@ -297,7 +301,8 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba, if (mvumi_internal_cmd_sgl(mhba, cmd, buf_size)) { dev_err(&mhba->pdev->dev, "failed to allocate memory" " for internal frame\n"); - kfree(cmd->frame); + pci_free_consistent(mhba->pdev, mhba->ib_max_size, + cmd->frame, cmd->frame_phys); kfree(cmd); return NULL; } @@ -317,7 +322,7 @@ static void mvumi_delete_internal_cmd(struct mvumi_hba *mhba, if (cmd && cmd->frame) { if (cmd->frame->sg_counts) { m_sg = (struct mvumi_sgl *) &cmd->frame->payload[0]; - size = m_sg->size; + sgd_getsz(mhba, m_sg, size); phy_addr = (dma_addr_t) m_sg->baseaddr_l | (dma_addr_t) ((m_sg->baseaddr_h << 16) << 16); @@ -325,7 +330,8 @@ static void mvumi_delete_internal_cmd(struct mvumi_hba *mhba, pci_free_consistent(mhba->pdev, size, cmd->data_buf, phy_addr); } - kfree(cmd->frame); + pci_free_consistent(mhba->pdev, mhba->ib_max_size, + cmd->frame, cmd->frame_phys); kfree(cmd); } } @@ -374,7 +380,8 @@ static void mvumi_free_cmds(struct mvumi_hba *mhba) cmd = list_first_entry(&mhba->cmd_pool, struct mvumi_cmd, queue_pointer); list_del(&cmd->queue_pointer); - kfree(cmd->frame); + if (!(mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC)) + kfree(cmd->frame); kfree(cmd); } } @@ -396,7 +403,12 @@ static int mvumi_alloc_cmds(struct mvumi_hba *mhba) INIT_LIST_HEAD(&cmd->queue_pointer); list_add_tail(&cmd->queue_pointer, &mhba->cmd_pool); - cmd->frame = kzalloc(mhba->ib_max_size, GFP_KERNEL); + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) { + cmd->frame = mhba->ib_frame + i * mhba->ib_max_size; + cmd->frame_phys = mhba->ib_frame_phys + + i * mhba->ib_max_size; + } else + cmd->frame = kzalloc(mhba->ib_max_size, GFP_KERNEL); if (!cmd->frame) goto err_exit; } @@ -409,48 +421,71 @@ err_exit: cmd = list_first_entry(&mhba->cmd_pool, struct mvumi_cmd, queue_pointer); list_del(&cmd->queue_pointer); - kfree(cmd->frame); + if (!(mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC)) + kfree(cmd->frame); kfree(cmd); } return -ENOMEM; } -static int mvumi_get_ib_list_entry(struct mvumi_hba *mhba, void **ib_entry) +static unsigned int mvumi_check_ib_list_9143(struct mvumi_hba *mhba) { - unsigned int ib_rp_reg, cur_ib_entry; + unsigned int ib_rp_reg; + struct mvumi_hw_regs *regs = mhba->regs; + + ib_rp_reg = ioread32(mhba->regs->inb_read_pointer); + if (unlikely(((ib_rp_reg & regs->cl_slot_num_mask) == + (mhba->ib_cur_slot & regs->cl_slot_num_mask)) && + ((ib_rp_reg & regs->cl_pointer_toggle) + != (mhba->ib_cur_slot & regs->cl_pointer_toggle)))) { + dev_warn(&mhba->pdev->dev, "no free slot to use.\n"); + return 0; + } if (atomic_read(&mhba->fw_outstanding) >= mhba->max_io) { dev_warn(&mhba->pdev->dev, "firmware io overflow.\n"); - return -1; + return 0; + } else { + return mhba->max_io - atomic_read(&mhba->fw_outstanding); } - ib_rp_reg = ioread32(mhba->mmio + CLA_INB_READ_POINTER); +} - if (unlikely(((ib_rp_reg & CL_SLOT_NUM_MASK) == - (mhba->ib_cur_slot & CL_SLOT_NUM_MASK)) && - ((ib_rp_reg & CL_POINTER_TOGGLE) != - (mhba->ib_cur_slot & CL_POINTER_TOGGLE)))) { - dev_warn(&mhba->pdev->dev, "no free slot to use.\n"); - return -1; - } +static unsigned int mvumi_check_ib_list_9580(struct mvumi_hba *mhba) +{ + unsigned int count; + if (atomic_read(&mhba->fw_outstanding) >= (mhba->max_io - 1)) + return 0; + count = ioread32(mhba->ib_shadow); + if (count == 0xffff) + return 0; + return count; +} + +static void mvumi_get_ib_list_entry(struct mvumi_hba *mhba, void **ib_entry) +{ + unsigned int cur_ib_entry; - cur_ib_entry = mhba->ib_cur_slot & CL_SLOT_NUM_MASK; + cur_ib_entry = mhba->ib_cur_slot & mhba->regs->cl_slot_num_mask; cur_ib_entry++; if (cur_ib_entry >= mhba->list_num_io) { cur_ib_entry -= mhba->list_num_io; - mhba->ib_cur_slot ^= CL_POINTER_TOGGLE; + mhba->ib_cur_slot ^= mhba->regs->cl_pointer_toggle; + } + mhba->ib_cur_slot &= ~mhba->regs->cl_slot_num_mask; + mhba->ib_cur_slot |= (cur_ib_entry & mhba->regs->cl_slot_num_mask); + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) { + *ib_entry = mhba->ib_list + cur_ib_entry * + sizeof(struct mvumi_dyn_list_entry); + } else { + *ib_entry = mhba->ib_list + cur_ib_entry * mhba->ib_max_size; } - mhba->ib_cur_slot &= ~CL_SLOT_NUM_MASK; - mhba->ib_cur_slot |= (cur_ib_entry & CL_SLOT_NUM_MASK); - *ib_entry = mhba->ib_list + cur_ib_entry * mhba->ib_max_size; atomic_inc(&mhba->fw_outstanding); - - return 0; } static void mvumi_send_ib_list_entry(struct mvumi_hba *mhba) { - iowrite32(0xfff, mhba->ib_shadow); - iowrite32(mhba->ib_cur_slot, mhba->mmio + CLA_INB_WRITE_POINTER); + iowrite32(0xffff, mhba->ib_shadow); + iowrite32(mhba->ib_cur_slot, mhba->regs->inb_write_pointer); } static char mvumi_check_ob_frame(struct mvumi_hba *mhba, @@ -480,31 +515,59 @@ static char mvumi_check_ob_frame(struct mvumi_hba *mhba, return 0; } -static void mvumi_receive_ob_list_entry(struct mvumi_hba *mhba) +static int mvumi_check_ob_list_9143(struct mvumi_hba *mhba, + unsigned int *cur_obf, unsigned int *assign_obf_end) { - unsigned int ob_write_reg, ob_write_shadow_reg; - unsigned int cur_obf, assign_obf_end, i; - struct mvumi_ob_data *ob_data; - struct mvumi_rsp_frame *p_outb_frame; + unsigned int ob_write, ob_write_shadow; + struct mvumi_hw_regs *regs = mhba->regs; do { - ob_write_reg = ioread32(mhba->mmio + CLA_OUTB_COPY_POINTER); - ob_write_shadow_reg = ioread32(mhba->ob_shadow); - } while ((ob_write_reg & CL_SLOT_NUM_MASK) != ob_write_shadow_reg); + ob_write = ioread32(regs->outb_copy_pointer); + ob_write_shadow = ioread32(mhba->ob_shadow); + } while ((ob_write & regs->cl_slot_num_mask) != ob_write_shadow); - cur_obf = mhba->ob_cur_slot & CL_SLOT_NUM_MASK; - assign_obf_end = ob_write_reg & CL_SLOT_NUM_MASK; + *cur_obf = mhba->ob_cur_slot & mhba->regs->cl_slot_num_mask; + *assign_obf_end = ob_write & mhba->regs->cl_slot_num_mask; - if ((ob_write_reg & CL_POINTER_TOGGLE) != - (mhba->ob_cur_slot & CL_POINTER_TOGGLE)) { - assign_obf_end += mhba->list_num_io; + if ((ob_write & regs->cl_pointer_toggle) != + (mhba->ob_cur_slot & regs->cl_pointer_toggle)) { + *assign_obf_end += mhba->list_num_io; } + return 0; +} + +static int mvumi_check_ob_list_9580(struct mvumi_hba *mhba, + unsigned int *cur_obf, unsigned int *assign_obf_end) +{ + unsigned int ob_write; + struct mvumi_hw_regs *regs = mhba->regs; + + ob_write = ioread32(regs->outb_read_pointer); + ob_write = ioread32(regs->outb_copy_pointer); + *cur_obf = mhba->ob_cur_slot & mhba->regs->cl_slot_num_mask; + *assign_obf_end = ob_write & mhba->regs->cl_slot_num_mask; + if (*assign_obf_end < *cur_obf) + *assign_obf_end += mhba->list_num_io; + else if (*assign_obf_end == *cur_obf) + return -1; + return 0; +} + +static void mvumi_receive_ob_list_entry(struct mvumi_hba *mhba) +{ + unsigned int cur_obf, assign_obf_end, i; + struct mvumi_ob_data *ob_data; + struct mvumi_rsp_frame *p_outb_frame; + struct mvumi_hw_regs *regs = mhba->regs; + + if (mhba->instancet->check_ob_list(mhba, &cur_obf, &assign_obf_end)) + return; for (i = (assign_obf_end - cur_obf); i != 0; i--) { cur_obf++; if (cur_obf >= mhba->list_num_io) { cur_obf -= mhba->list_num_io; - mhba->ob_cur_slot ^= CL_POINTER_TOGGLE; + mhba->ob_cur_slot ^= regs->cl_pointer_toggle; } p_outb_frame = mhba->ob_list + cur_obf * mhba->ob_max_size; @@ -528,7 +591,7 @@ static void mvumi_receive_ob_list_entry(struct mvumi_hba *mhba) ob_data = NULL; if (cur_obf == 0) { cur_obf = mhba->list_num_io - 1; - mhba->ob_cur_slot ^= CL_POINTER_TOGGLE; + mhba->ob_cur_slot ^= regs->cl_pointer_toggle; } else cur_obf -= 1; break; @@ -539,18 +602,20 @@ static void mvumi_receive_ob_list_entry(struct mvumi_hba *mhba) list_add_tail(&ob_data->list, &mhba->free_ob_list); } - mhba->ob_cur_slot &= ~CL_SLOT_NUM_MASK; - mhba->ob_cur_slot |= (cur_obf & CL_SLOT_NUM_MASK); - iowrite32(mhba->ob_cur_slot, mhba->mmio + CLA_OUTB_READ_POINTER); + mhba->ob_cur_slot &= ~regs->cl_slot_num_mask; + mhba->ob_cur_slot |= (cur_obf & regs->cl_slot_num_mask); + iowrite32(mhba->ob_cur_slot, regs->outb_read_pointer); } -static void mvumi_reset(void *regs) +static void mvumi_reset(struct mvumi_hba *mhba) { - iowrite32(0, regs + CPU_ENPOINTA_MASK_REG); - if (ioread32(regs + CPU_ARM_TO_PCIEA_MSG1) != HANDSHAKE_DONESTATE) + struct mvumi_hw_regs *regs = mhba->regs; + + iowrite32(0, regs->enpointa_mask_reg); + if (ioread32(regs->arm_to_pciea_msg1) != HANDSHAKE_DONESTATE) return; - iowrite32(DRBL_SOFT_RESET, regs + CPU_PCIEA_TO_ARM_DRBL_REG); + iowrite32(DRBL_SOFT_RESET, regs->pciea_to_arm_drbl_reg); } static unsigned char mvumi_start(struct mvumi_hba *mhba); @@ -558,7 +623,7 @@ static unsigned char mvumi_start(struct mvumi_hba *mhba); static int mvumi_wait_for_outstanding(struct mvumi_hba *mhba) { mhba->fw_state = FW_STATE_ABORT; - mvumi_reset(mhba->mmio); + mvumi_reset(mhba); if (mvumi_start(mhba)) return FAILED; @@ -566,6 +631,98 @@ static int mvumi_wait_for_outstanding(struct mvumi_hba *mhba) return SUCCESS; } +static int mvumi_wait_for_fw(struct mvumi_hba *mhba) +{ + struct mvumi_hw_regs *regs = mhba->regs; + u32 tmp; + unsigned long before; + before = jiffies; + + iowrite32(0, regs->enpointa_mask_reg); + tmp = ioread32(regs->arm_to_pciea_msg1); + while (tmp != HANDSHAKE_READYSTATE) { + iowrite32(DRBL_MU_RESET, regs->pciea_to_arm_drbl_reg); + if (time_after(jiffies, before + FW_MAX_DELAY * HZ)) { + dev_err(&mhba->pdev->dev, + "FW reset failed [0x%x].\n", tmp); + return FAILED; + } + + msleep(500); + rmb(); + tmp = ioread32(regs->arm_to_pciea_msg1); + } + + return SUCCESS; +} + +static void mvumi_backup_bar_addr(struct mvumi_hba *mhba) +{ + unsigned char i; + + for (i = 0; i < MAX_BASE_ADDRESS; i++) { + pci_read_config_dword(mhba->pdev, 0x10 + i * 4, + &mhba->pci_base[i]); + } +} + +static void mvumi_restore_bar_addr(struct mvumi_hba *mhba) +{ + unsigned char i; + + for (i = 0; i < MAX_BASE_ADDRESS; i++) { + if (mhba->pci_base[i]) + pci_write_config_dword(mhba->pdev, 0x10 + i * 4, + mhba->pci_base[i]); + } +} + +static unsigned int mvumi_pci_set_master(struct pci_dev *pdev) +{ + unsigned int ret = 0; + pci_set_master(pdev); + + if (IS_DMA64) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + } else + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + + return ret; +} + +static int mvumi_reset_host_9580(struct mvumi_hba *mhba) +{ + mhba->fw_state = FW_STATE_ABORT; + + iowrite32(0, mhba->regs->reset_enable); + iowrite32(0xf, mhba->regs->reset_request); + + iowrite32(0x10, mhba->regs->reset_enable); + iowrite32(0x10, mhba->regs->reset_request); + msleep(100); + pci_disable_device(mhba->pdev); + + if (pci_enable_device(mhba->pdev)) { + dev_err(&mhba->pdev->dev, "enable device failed\n"); + return FAILED; + } + if (mvumi_pci_set_master(mhba->pdev)) { + dev_err(&mhba->pdev->dev, "set master failed\n"); + return FAILED; + } + mvumi_restore_bar_addr(mhba); + if (mvumi_wait_for_fw(mhba) == FAILED) + return FAILED; + + return mvumi_wait_for_outstanding(mhba); +} + +static int mvumi_reset_host_9143(struct mvumi_hba *mhba) +{ + return mvumi_wait_for_outstanding(mhba); +} + static int mvumi_host_reset(struct scsi_cmnd *scmd) { struct mvumi_hba *mhba; @@ -575,7 +732,7 @@ static int mvumi_host_reset(struct scsi_cmnd *scmd) scmd_printk(KERN_NOTICE, scmd, "RESET -%ld cmd=%x retries=%x\n", scmd->serial_number, scmd->cmnd[0], scmd->retries); - return mvumi_wait_for_outstanding(mhba); + return mhba->instancet->reset_host(mhba); } static int mvumi_issue_blocked_cmd(struct mvumi_hba *mhba, @@ -628,7 +785,9 @@ static void mvumi_release_fw(struct mvumi_hba *mhba) mvumi_free_cmds(mhba); mvumi_release_mem_resource(mhba); mvumi_unmap_pci_addr(mhba->pdev, mhba->base_addr); - kfree(mhba->handshake_page); + pci_free_consistent(mhba->pdev, HSP_MAX_SIZE, + mhba->handshake_page, mhba->handshake_page_phys); + kfree(mhba->regs); pci_release_regions(mhba->pdev); } @@ -665,6 +824,7 @@ get_cmd: cmd = mvumi_create_internal_cmd(mhba, 0); frame->cdb_length = MAX_COMMAND_SIZE; memset(frame->cdb, 0, MAX_COMMAND_SIZE); frame->cdb[0] = SCSI_CMD_MARVELL_SPECIFIC; + frame->cdb[1] = CDB_CORE_MODULE; frame->cdb[2] = CDB_CORE_SHUTDOWN; mvumi_issue_blocked_cmd(mhba, cmd); @@ -695,7 +855,7 @@ mvumi_calculate_checksum(struct mvumi_hs_header *p_header, return ret; } -void mvumi_hs_build_page(struct mvumi_hba *mhba, +static void mvumi_hs_build_page(struct mvumi_hba *mhba, struct mvumi_hs_header *hs_header) { struct mvumi_hs_page2 *hs_page2; @@ -710,6 +870,8 @@ void mvumi_hs_build_page(struct mvumi_hba *mhba, hs_header->frame_length = sizeof(*hs_page2) - 4; memset(hs_header->frame_content, 0, hs_header->frame_length); hs_page2->host_type = 3; /* 3 mean linux*/ + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) + hs_page2->host_cap = 0x08;/* host dynamic source mode */ hs_page2->host_ver.ver_major = VER_MAJOR; hs_page2->host_ver.ver_minor = VER_MINOR; hs_page2->host_ver.ver_oem = VER_OEM; @@ -745,8 +907,18 @@ void mvumi_hs_build_page(struct mvumi_hba *mhba, hs_page4->ob_baseaddr_h = upper_32_bits(mhba->ob_list_phys); hs_page4->ib_entry_size = mhba->ib_max_size_setting; hs_page4->ob_entry_size = mhba->ob_max_size_setting; - hs_page4->ob_depth = mhba->list_num_io; - hs_page4->ib_depth = mhba->list_num_io; + if (mhba->hba_capability + & HS_CAPABILITY_NEW_PAGE_IO_DEPTH_DEF) { + hs_page4->ob_depth = find_first_bit((unsigned long *) + &mhba->list_num_io, + BITS_PER_LONG); + hs_page4->ib_depth = find_first_bit((unsigned long *) + &mhba->list_num_io, + BITS_PER_LONG); + } else { + hs_page4->ob_depth = (u8) mhba->list_num_io; + hs_page4->ib_depth = (u8) mhba->list_num_io; + } hs_header->checksum = mvumi_calculate_checksum(hs_header, hs_header->frame_length); break; @@ -774,8 +946,11 @@ static int mvumi_init_data(struct mvumi_hba *mhba) return 0; tmp_size = mhba->ib_max_size * mhba->max_io; + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) + tmp_size += sizeof(struct mvumi_dyn_list_entry) * mhba->max_io; + tmp_size += 128 + mhba->ob_max_size * mhba->max_io; - tmp_size += 8 + sizeof(u32) + 16; + tmp_size += 8 + sizeof(u32)*2 + 16; res_mgnt = mvumi_alloc_mem_resource(mhba, RESOURCE_UNCACHED_MEMORY, tmp_size); @@ -793,24 +968,41 @@ static int mvumi_init_data(struct mvumi_hba *mhba) v += offset; mhba->ib_list = v; mhba->ib_list_phys = p; + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) { + v += sizeof(struct mvumi_dyn_list_entry) * mhba->max_io; + p += sizeof(struct mvumi_dyn_list_entry) * mhba->max_io; + mhba->ib_frame = v; + mhba->ib_frame_phys = p; + } v += mhba->ib_max_size * mhba->max_io; p += mhba->ib_max_size * mhba->max_io; + /* ib shadow */ offset = round_up(p, 8) - p; p += offset; v += offset; mhba->ib_shadow = v; mhba->ib_shadow_phys = p; - p += sizeof(u32); - v += sizeof(u32); + p += sizeof(u32)*2; + v += sizeof(u32)*2; /* ob shadow */ - offset = round_up(p, 8) - p; - p += offset; - v += offset; - mhba->ob_shadow = v; - mhba->ob_shadow_phys = p; - p += 8; - v += 8; + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9580) { + offset = round_up(p, 8) - p; + p += offset; + v += offset; + mhba->ob_shadow = v; + mhba->ob_shadow_phys = p; + p += 8; + v += 8; + } else { + offset = round_up(p, 4) - p; + p += offset; + v += offset; + mhba->ob_shadow = v; + mhba->ob_shadow_phys = p; + p += 4; + v += 4; + } /* ob list */ offset = round_up(p, 128) - p; @@ -902,6 +1094,12 @@ static int mvumi_hs_process_page(struct mvumi_hba *mhba, dev_dbg(&mhba->pdev->dev, "FW version:%d\n", hs_page1->fw_ver.ver_build); + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG) + mhba->eot_flag = 22; + else + mhba->eot_flag = 27; + if (mhba->hba_capability & HS_CAPABILITY_NEW_PAGE_IO_DEPTH_DEF) + mhba->list_num_io = 1 << hs_page1->cl_inout_list_depth; break; default: dev_err(&mhba->pdev->dev, "handshake: page code error\n"); @@ -923,12 +1121,12 @@ static int mvumi_handshake(struct mvumi_hba *mhba) { unsigned int hs_state, tmp, hs_fun; struct mvumi_hs_header *hs_header; - void *regs = mhba->mmio; + struct mvumi_hw_regs *regs = mhba->regs; if (mhba->fw_state == FW_STATE_STARTING) hs_state = HS_S_START; else { - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_MSG0); + tmp = ioread32(regs->arm_to_pciea_msg0); hs_state = HS_GET_STATE(tmp); dev_dbg(&mhba->pdev->dev, "handshake state[0x%x].\n", hs_state); if (HS_GET_STATUS(tmp) != HS_STATUS_OK) { @@ -943,21 +1141,20 @@ static int mvumi_handshake(struct mvumi_hba *mhba) mhba->fw_state = FW_STATE_HANDSHAKING; HS_SET_STATUS(hs_fun, HS_STATUS_OK); HS_SET_STATE(hs_fun, HS_S_RESET); - iowrite32(HANDSHAKE_SIGNATURE, regs + CPU_PCIEA_TO_ARM_MSG1); - iowrite32(hs_fun, regs + CPU_PCIEA_TO_ARM_MSG0); - iowrite32(DRBL_HANDSHAKE, regs + CPU_PCIEA_TO_ARM_DRBL_REG); + iowrite32(HANDSHAKE_SIGNATURE, regs->pciea_to_arm_msg1); + iowrite32(hs_fun, regs->pciea_to_arm_msg0); + iowrite32(DRBL_HANDSHAKE, regs->pciea_to_arm_drbl_reg); break; case HS_S_RESET: iowrite32(lower_32_bits(mhba->handshake_page_phys), - regs + CPU_PCIEA_TO_ARM_MSG1); + regs->pciea_to_arm_msg1); iowrite32(upper_32_bits(mhba->handshake_page_phys), - regs + CPU_ARM_TO_PCIEA_MSG1); + regs->arm_to_pciea_msg1); HS_SET_STATUS(hs_fun, HS_STATUS_OK); HS_SET_STATE(hs_fun, HS_S_PAGE_ADDR); - iowrite32(hs_fun, regs + CPU_PCIEA_TO_ARM_MSG0); - iowrite32(DRBL_HANDSHAKE, regs + CPU_PCIEA_TO_ARM_DRBL_REG); - + iowrite32(hs_fun, regs->pciea_to_arm_msg0); + iowrite32(DRBL_HANDSHAKE, regs->pciea_to_arm_drbl_reg); break; case HS_S_PAGE_ADDR: @@ -997,30 +1194,37 @@ static int mvumi_handshake(struct mvumi_hba *mhba) HS_SET_STATE(hs_fun, HS_S_END); HS_SET_STATUS(hs_fun, HS_STATUS_OK); - iowrite32(hs_fun, regs + CPU_PCIEA_TO_ARM_MSG0); - iowrite32(DRBL_HANDSHAKE, regs + CPU_PCIEA_TO_ARM_DRBL_REG); + iowrite32(hs_fun, regs->pciea_to_arm_msg0); + iowrite32(DRBL_HANDSHAKE, regs->pciea_to_arm_drbl_reg); break; case HS_S_END: /* Set communication list ISR */ - tmp = ioread32(regs + CPU_ENPOINTA_MASK_REG); - tmp |= INT_MAP_COMAOUT | INT_MAP_COMAERR; - iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG); + tmp = ioread32(regs->enpointa_mask_reg); + tmp |= regs->int_comaout | regs->int_comaerr; + iowrite32(tmp, regs->enpointa_mask_reg); iowrite32(mhba->list_num_io, mhba->ib_shadow); /* Set InBound List Available count shadow */ iowrite32(lower_32_bits(mhba->ib_shadow_phys), - regs + CLA_INB_AVAL_COUNT_BASEL); + regs->inb_aval_count_basel); iowrite32(upper_32_bits(mhba->ib_shadow_phys), - regs + CLA_INB_AVAL_COUNT_BASEH); - - /* Set OutBound List Available count shadow */ - iowrite32((mhba->list_num_io-1) | CL_POINTER_TOGGLE, - mhba->ob_shadow); - iowrite32(lower_32_bits(mhba->ob_shadow_phys), regs + 0x5B0); - iowrite32(upper_32_bits(mhba->ob_shadow_phys), regs + 0x5B4); + regs->inb_aval_count_baseh); + + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9143) { + /* Set OutBound List Available count shadow */ + iowrite32((mhba->list_num_io-1) | + regs->cl_pointer_toggle, + mhba->ob_shadow); + iowrite32(lower_32_bits(mhba->ob_shadow_phys), + regs->outb_copy_basel); + iowrite32(upper_32_bits(mhba->ob_shadow_phys), + regs->outb_copy_baseh); + } - mhba->ib_cur_slot = (mhba->list_num_io - 1) | CL_POINTER_TOGGLE; - mhba->ob_cur_slot = (mhba->list_num_io - 1) | CL_POINTER_TOGGLE; + mhba->ib_cur_slot = (mhba->list_num_io - 1) | + regs->cl_pointer_toggle; + mhba->ob_cur_slot = (mhba->list_num_io - 1) | + regs->cl_pointer_toggle; mhba->fw_state = FW_STATE_STARTED; break; @@ -1040,7 +1244,7 @@ static unsigned char mvumi_handshake_event(struct mvumi_hba *mhba) before = jiffies; mvumi_handshake(mhba); do { - isr_status = mhba->instancet->read_fw_status_reg(mhba->mmio); + isr_status = mhba->instancet->read_fw_status_reg(mhba); if (mhba->fw_state == FW_STATE_STARTED) return 0; @@ -1062,16 +1266,15 @@ static unsigned char mvumi_handshake_event(struct mvumi_hba *mhba) static unsigned char mvumi_check_handshake(struct mvumi_hba *mhba) { - void *regs = mhba->mmio; unsigned int tmp; unsigned long before; before = jiffies; - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_MSG1); + tmp = ioread32(mhba->regs->arm_to_pciea_msg1); while ((tmp != HANDSHAKE_READYSTATE) && (tmp != HANDSHAKE_DONESTATE)) { if (tmp != HANDSHAKE_READYSTATE) iowrite32(DRBL_MU_RESET, - regs + CPU_PCIEA_TO_ARM_DRBL_REG); + mhba->regs->pciea_to_arm_drbl_reg); if (time_after(jiffies, before + FW_MAX_DELAY * HZ)) { dev_err(&mhba->pdev->dev, "invalid signature [0x%x].\n", tmp); @@ -1079,7 +1282,7 @@ static unsigned char mvumi_check_handshake(struct mvumi_hba *mhba) } usleep_range(1000, 2000); rmb(); - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_MSG1); + tmp = ioread32(mhba->regs->arm_to_pciea_msg1); } mhba->fw_state = FW_STATE_STARTING; @@ -1100,15 +1303,17 @@ static unsigned char mvumi_check_handshake(struct mvumi_hba *mhba) static unsigned char mvumi_start(struct mvumi_hba *mhba) { - void *regs = mhba->mmio; unsigned int tmp; + struct mvumi_hw_regs *regs = mhba->regs; + /* clear Door bell */ - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_DRBL_REG); - iowrite32(tmp, regs + CPU_ARM_TO_PCIEA_DRBL_REG); + tmp = ioread32(regs->arm_to_pciea_drbl_reg); + iowrite32(tmp, regs->arm_to_pciea_drbl_reg); - iowrite32(0x3FFFFFFF, regs + CPU_ARM_TO_PCIEA_MASK_REG); - tmp = ioread32(regs + CPU_ENPOINTA_MASK_REG) | INT_MAP_DL_CPU2PCIEA; - iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG); + iowrite32(regs->int_drbl_int_mask, regs->arm_to_pciea_mask_reg); + tmp = ioread32(regs->enpointa_mask_reg) | regs->int_dl_cpu2pciea; + iowrite32(tmp, regs->enpointa_mask_reg); + msleep(100); if (mvumi_check_handshake(mhba)) return -1; @@ -1166,6 +1371,7 @@ static void mvumi_complete_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, cmd->scmd->scsi_done(scmd); mvumi_return_cmd(mhba, cmd); } + static void mvumi_complete_internal_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, struct mvumi_rsp_frame *ob_frame) @@ -1210,6 +1416,304 @@ static void mvumi_show_event(struct mvumi_hba *mhba, } } +static int mvumi_handle_hotplug(struct mvumi_hba *mhba, u16 devid, int status) +{ + struct scsi_device *sdev; + int ret = -1; + + if (status == DEVICE_OFFLINE) { + sdev = scsi_device_lookup(mhba->shost, 0, devid, 0); + if (sdev) { + dev_dbg(&mhba->pdev->dev, "remove disk %d-%d-%d.\n", 0, + sdev->id, 0); + scsi_remove_device(sdev); + scsi_device_put(sdev); + ret = 0; + } else + dev_err(&mhba->pdev->dev, " no disk[%d] to remove\n", + devid); + } else if (status == DEVICE_ONLINE) { + sdev = scsi_device_lookup(mhba->shost, 0, devid, 0); + if (!sdev) { + scsi_add_device(mhba->shost, 0, devid, 0); + dev_dbg(&mhba->pdev->dev, " add disk %d-%d-%d.\n", 0, + devid, 0); + ret = 0; + } else { + dev_err(&mhba->pdev->dev, " don't add disk %d-%d-%d.\n", + 0, devid, 0); + scsi_device_put(sdev); + } + } + return ret; +} + +static u64 mvumi_inquiry(struct mvumi_hba *mhba, + unsigned int id, struct mvumi_cmd *cmd) +{ + struct mvumi_msg_frame *frame; + u64 wwid = 0; + int cmd_alloc = 0; + int data_buf_len = 64; + + if (!cmd) { + cmd = mvumi_create_internal_cmd(mhba, data_buf_len); + if (cmd) + cmd_alloc = 1; + else + return 0; + } else { + memset(cmd->data_buf, 0, data_buf_len); + } + cmd->scmd = NULL; + cmd->cmd_status = REQ_STATUS_PENDING; + atomic_set(&cmd->sync_cmd, 0); + frame = cmd->frame; + frame->device_id = (u16) id; + frame->cmd_flag = CMD_FLAG_DATA_IN; + frame->req_function = CL_FUN_SCSI_CMD; + frame->cdb_length = 6; + frame->data_transfer_length = MVUMI_INQUIRY_LENGTH; + memset(frame->cdb, 0, frame->cdb_length); + frame->cdb[0] = INQUIRY; + frame->cdb[4] = frame->data_transfer_length; + + mvumi_issue_blocked_cmd(mhba, cmd); + + if (cmd->cmd_status == SAM_STAT_GOOD) { + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9143) + wwid = id + 1; + else + memcpy((void *)&wwid, + (cmd->data_buf + MVUMI_INQUIRY_UUID_OFF), + MVUMI_INQUIRY_UUID_LEN); + dev_dbg(&mhba->pdev->dev, + "inquiry device(0:%d:0) wwid(%llx)\n", id, wwid); + } else { + wwid = 0; + } + if (cmd_alloc) + mvumi_delete_internal_cmd(mhba, cmd); + + return wwid; +} + +static void mvumi_detach_devices(struct mvumi_hba *mhba) +{ + struct mvumi_device *mv_dev = NULL , *dev_next; + struct scsi_device *sdev = NULL; + + mutex_lock(&mhba->device_lock); + + /* detach Hard Disk */ + list_for_each_entry_safe(mv_dev, dev_next, + &mhba->shost_dev_list, list) { + mvumi_handle_hotplug(mhba, mv_dev->id, DEVICE_OFFLINE); + list_del_init(&mv_dev->list); + dev_dbg(&mhba->pdev->dev, "release device(0:%d:0) wwid(%llx)\n", + mv_dev->id, mv_dev->wwid); + kfree(mv_dev); + } + list_for_each_entry_safe(mv_dev, dev_next, &mhba->mhba_dev_list, list) { + list_del_init(&mv_dev->list); + dev_dbg(&mhba->pdev->dev, "release device(0:%d:0) wwid(%llx)\n", + mv_dev->id, mv_dev->wwid); + kfree(mv_dev); + } + + /* detach virtual device */ + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9580) + sdev = scsi_device_lookup(mhba->shost, 0, + mhba->max_target_id - 1, 0); + + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + + mutex_unlock(&mhba->device_lock); +} + +static void mvumi_rescan_devices(struct mvumi_hba *mhba, int id) +{ + struct scsi_device *sdev; + + sdev = scsi_device_lookup(mhba->shost, 0, id, 0); + if (sdev) { + scsi_rescan_device(&sdev->sdev_gendev); + scsi_device_put(sdev); + } +} + +static int mvumi_match_devices(struct mvumi_hba *mhba, int id, u64 wwid) +{ + struct mvumi_device *mv_dev = NULL; + + list_for_each_entry(mv_dev, &mhba->shost_dev_list, list) { + if (mv_dev->wwid == wwid) { + if (mv_dev->id != id) { + dev_err(&mhba->pdev->dev, + "%s has same wwid[%llx] ," + " but different id[%d %d]\n", + __func__, mv_dev->wwid, mv_dev->id, id); + return -1; + } else { + if (mhba->pdev->device == + PCI_DEVICE_ID_MARVELL_MV9143) + mvumi_rescan_devices(mhba, id); + return 1; + } + } + } + return 0; +} + +static void mvumi_remove_devices(struct mvumi_hba *mhba, int id) +{ + struct mvumi_device *mv_dev = NULL, *dev_next; + + list_for_each_entry_safe(mv_dev, dev_next, + &mhba->shost_dev_list, list) { + if (mv_dev->id == id) { + dev_dbg(&mhba->pdev->dev, + "detach device(0:%d:0) wwid(%llx) from HOST\n", + mv_dev->id, mv_dev->wwid); + mvumi_handle_hotplug(mhba, mv_dev->id, DEVICE_OFFLINE); + list_del_init(&mv_dev->list); + kfree(mv_dev); + } + } +} + +static int mvumi_probe_devices(struct mvumi_hba *mhba) +{ + int id, maxid; + u64 wwid = 0; + struct mvumi_device *mv_dev = NULL; + struct mvumi_cmd *cmd = NULL; + int found = 0; + + cmd = mvumi_create_internal_cmd(mhba, 64); + if (!cmd) + return -1; + + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9143) + maxid = mhba->max_target_id; + else + maxid = mhba->max_target_id - 1; + + for (id = 0; id < maxid; id++) { + wwid = mvumi_inquiry(mhba, id, cmd); + if (!wwid) { + /* device no response, remove it */ + mvumi_remove_devices(mhba, id); + } else { + /* device response, add it */ + found = mvumi_match_devices(mhba, id, wwid); + if (!found) { + mvumi_remove_devices(mhba, id); + mv_dev = kzalloc(sizeof(struct mvumi_device), + GFP_KERNEL); + if (!mv_dev) { + dev_err(&mhba->pdev->dev, + "%s alloc mv_dev failed\n", + __func__); + continue; + } + mv_dev->id = id; + mv_dev->wwid = wwid; + mv_dev->sdev = NULL; + INIT_LIST_HEAD(&mv_dev->list); + list_add_tail(&mv_dev->list, + &mhba->mhba_dev_list); + dev_dbg(&mhba->pdev->dev, + "probe a new device(0:%d:0)" + " wwid(%llx)\n", id, mv_dev->wwid); + } else if (found == -1) + return -1; + else + continue; + } + } + + if (cmd) + mvumi_delete_internal_cmd(mhba, cmd); + + return 0; +} + +static int mvumi_rescan_bus(void *data) +{ + int ret = 0; + struct mvumi_hba *mhba = (struct mvumi_hba *) data; + struct mvumi_device *mv_dev = NULL , *dev_next; + + while (!kthread_should_stop()) { + + set_current_state(TASK_INTERRUPTIBLE); + if (!atomic_read(&mhba->pnp_count)) + schedule(); + msleep(1000); + atomic_set(&mhba->pnp_count, 0); + __set_current_state(TASK_RUNNING); + + mutex_lock(&mhba->device_lock); + ret = mvumi_probe_devices(mhba); + if (!ret) { + list_for_each_entry_safe(mv_dev, dev_next, + &mhba->mhba_dev_list, list) { + if (mvumi_handle_hotplug(mhba, mv_dev->id, + DEVICE_ONLINE)) { + dev_err(&mhba->pdev->dev, + "%s add device(0:%d:0) failed" + "wwid(%llx) has exist\n", + __func__, + mv_dev->id, mv_dev->wwid); + list_del_init(&mv_dev->list); + kfree(mv_dev); + } else { + list_move_tail(&mv_dev->list, + &mhba->shost_dev_list); + } + } + } + mutex_unlock(&mhba->device_lock); + } + return 0; +} + +static void mvumi_proc_msg(struct mvumi_hba *mhba, + struct mvumi_hotplug_event *param) +{ + u16 size = param->size; + const unsigned long *ar_bitmap; + const unsigned long *re_bitmap; + int index; + + if (mhba->fw_flag & MVUMI_FW_ATTACH) { + index = -1; + ar_bitmap = (const unsigned long *) param->bitmap; + re_bitmap = (const unsigned long *) ¶m->bitmap[size >> 3]; + + mutex_lock(&mhba->sas_discovery_mutex); + do { + index = find_next_zero_bit(ar_bitmap, size, index + 1); + if (index >= size) + break; + mvumi_handle_hotplug(mhba, index, DEVICE_ONLINE); + } while (1); + + index = -1; + do { + index = find_next_zero_bit(re_bitmap, size, index + 1); + if (index >= size) + break; + mvumi_handle_hotplug(mhba, index, DEVICE_OFFLINE); + } while (1); + mutex_unlock(&mhba->sas_discovery_mutex); + } +} + static void mvumi_notification(struct mvumi_hba *mhba, u8 msg, void *buffer) { if (msg == APICDB1_EVENT_GETEVENT) { @@ -1227,6 +1731,8 @@ static void mvumi_notification(struct mvumi_hba *mhba, u8 msg, void *buffer) param = &er->events[i]; mvumi_show_event(mhba, param); } + } else if (msg == APICDB1_HOST_GETEVENT) { + mvumi_proc_msg(mhba, buffer); } } @@ -1271,17 +1777,27 @@ static void mvumi_scan_events(struct work_struct *work) kfree(mu_ev); } -static void mvumi_launch_events(struct mvumi_hba *mhba, u8 msg) +static void mvumi_launch_events(struct mvumi_hba *mhba, u32 isr_status) { struct mvumi_events_wq *mu_ev; - mu_ev = kzalloc(sizeof(*mu_ev), GFP_ATOMIC); - if (mu_ev) { - INIT_WORK(&mu_ev->work_q, mvumi_scan_events); - mu_ev->mhba = mhba; - mu_ev->event = msg; - mu_ev->param = NULL; - schedule_work(&mu_ev->work_q); + while (isr_status & (DRBL_BUS_CHANGE | DRBL_EVENT_NOTIFY)) { + if (isr_status & DRBL_BUS_CHANGE) { + atomic_inc(&mhba->pnp_count); + wake_up_process(mhba->dm_thread); + isr_status &= ~(DRBL_BUS_CHANGE); + continue; + } + + mu_ev = kzalloc(sizeof(*mu_ev), GFP_ATOMIC); + if (mu_ev) { + INIT_WORK(&mu_ev->work_q, mvumi_scan_events); + mu_ev->mhba = mhba; + mu_ev->event = APICDB1_EVENT_GETEVENT; + isr_status &= ~(DRBL_EVENT_NOTIFY); + mu_ev->param = NULL; + schedule_work(&mu_ev->work_q); + } } } @@ -1322,16 +1838,17 @@ static irqreturn_t mvumi_isr_handler(int irq, void *devp) return IRQ_NONE; } - if (mhba->global_isr & INT_MAP_DL_CPU2PCIEA) { + if (mhba->global_isr & mhba->regs->int_dl_cpu2pciea) { + if (mhba->isr_status & (DRBL_BUS_CHANGE | DRBL_EVENT_NOTIFY)) + mvumi_launch_events(mhba, mhba->isr_status); if (mhba->isr_status & DRBL_HANDSHAKE_ISR) { dev_warn(&mhba->pdev->dev, "enter handshake again!\n"); mvumi_handshake(mhba); } - if (mhba->isr_status & DRBL_EVENT_NOTIFY) - mvumi_launch_events(mhba, APICDB1_EVENT_GETEVENT); + } - if (mhba->global_isr & INT_MAP_COMAOUT) + if (mhba->global_isr & mhba->regs->int_comaout) mvumi_receive_ob_list_entry(mhba); mhba->global_isr = 0; @@ -1358,8 +1875,7 @@ static enum mvumi_qc_result mvumi_send_command(struct mvumi_hba *mhba, dev_dbg(&mhba->pdev->dev, "no free tag.\n"); return MV_QUEUE_COMMAND_RESULT_NO_RESOURCE; } - if (mvumi_get_ib_list_entry(mhba, &ib_entry)) - return MV_QUEUE_COMMAND_RESULT_NO_RESOURCE; + mvumi_get_ib_list_entry(mhba, &ib_entry); cmd->frame->tag = tag_get_one(mhba, &mhba->tag_pool); cmd->frame->request_id = mhba->io_seq++; @@ -1367,21 +1883,35 @@ static enum mvumi_qc_result mvumi_send_command(struct mvumi_hba *mhba, mhba->tag_cmd[cmd->frame->tag] = cmd; frame_len = sizeof(*ib_frame) - 4 + ib_frame->sg_counts * sizeof(struct mvumi_sgl); - memcpy(ib_entry, ib_frame, frame_len); + if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) { + struct mvumi_dyn_list_entry *dle; + dle = ib_entry; + dle->src_low_addr = + cpu_to_le32(lower_32_bits(cmd->frame_phys)); + dle->src_high_addr = + cpu_to_le32(upper_32_bits(cmd->frame_phys)); + dle->if_length = (frame_len >> 2) & 0xFFF; + } else { + memcpy(ib_entry, ib_frame, frame_len); + } return MV_QUEUE_COMMAND_RESULT_SENT; } static void mvumi_fire_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd) { unsigned short num_of_cl_sent = 0; + unsigned int count; enum mvumi_qc_result result; if (cmd) list_add_tail(&cmd->queue_pointer, &mhba->waiting_req_list); + count = mhba->instancet->check_ib_list(mhba); + if (list_empty(&mhba->waiting_req_list) || !count) + return; - while (!list_empty(&mhba->waiting_req_list)) { + do { cmd = list_first_entry(&mhba->waiting_req_list, - struct mvumi_cmd, queue_pointer); + struct mvumi_cmd, queue_pointer); list_del_init(&cmd->queue_pointer); result = mvumi_send_command(mhba, cmd); switch (result) { @@ -1395,65 +1925,77 @@ static void mvumi_fire_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd) return; } - } + } while (!list_empty(&mhba->waiting_req_list) && count--); + if (num_of_cl_sent > 0) mvumi_send_ib_list_entry(mhba); } /** * mvumi_enable_intr - Enables interrupts - * @regs: FW register set + * @mhba: Adapter soft state */ -static void mvumi_enable_intr(void *regs) +static void mvumi_enable_intr(struct mvumi_hba *mhba) { unsigned int mask; + struct mvumi_hw_regs *regs = mhba->regs; - iowrite32(0x3FFFFFFF, regs + CPU_ARM_TO_PCIEA_MASK_REG); - mask = ioread32(regs + CPU_ENPOINTA_MASK_REG); - mask |= INT_MAP_DL_CPU2PCIEA | INT_MAP_COMAOUT | INT_MAP_COMAERR; - iowrite32(mask, regs + CPU_ENPOINTA_MASK_REG); + iowrite32(regs->int_drbl_int_mask, regs->arm_to_pciea_mask_reg); + mask = ioread32(regs->enpointa_mask_reg); + mask |= regs->int_dl_cpu2pciea | regs->int_comaout | regs->int_comaerr; + iowrite32(mask, regs->enpointa_mask_reg); } /** * mvumi_disable_intr -Disables interrupt - * @regs: FW register set + * @mhba: Adapter soft state */ -static void mvumi_disable_intr(void *regs) +static void mvumi_disable_intr(struct mvumi_hba *mhba) { unsigned int mask; + struct mvumi_hw_regs *regs = mhba->regs; - iowrite32(0, regs + CPU_ARM_TO_PCIEA_MASK_REG); - mask = ioread32(regs + CPU_ENPOINTA_MASK_REG); - mask &= ~(INT_MAP_DL_CPU2PCIEA | INT_MAP_COMAOUT | INT_MAP_COMAERR); - iowrite32(mask, regs + CPU_ENPOINTA_MASK_REG); + iowrite32(0, regs->arm_to_pciea_mask_reg); + mask = ioread32(regs->enpointa_mask_reg); + mask &= ~(regs->int_dl_cpu2pciea | regs->int_comaout | + regs->int_comaerr); + iowrite32(mask, regs->enpointa_mask_reg); } static int mvumi_clear_intr(void *extend) { struct mvumi_hba *mhba = (struct mvumi_hba *) extend; unsigned int status, isr_status = 0, tmp = 0; - void *regs = mhba->mmio; + struct mvumi_hw_regs *regs = mhba->regs; - status = ioread32(regs + CPU_MAIN_INT_CAUSE_REG); - if (!(status & INT_MAP_MU) || status == 0xFFFFFFFF) + status = ioread32(regs->main_int_cause_reg); + if (!(status & regs->int_mu) || status == 0xFFFFFFFF) return 1; - if (unlikely(status & INT_MAP_COMAERR)) { - tmp = ioread32(regs + CLA_ISR_CAUSE); - if (tmp & (CLIC_IN_ERR_IRQ | CLIC_OUT_ERR_IRQ)) - iowrite32(tmp & (CLIC_IN_ERR_IRQ | CLIC_OUT_ERR_IRQ), - regs + CLA_ISR_CAUSE); - status ^= INT_MAP_COMAERR; + if (unlikely(status & regs->int_comaerr)) { + tmp = ioread32(regs->outb_isr_cause); + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9580) { + if (tmp & regs->clic_out_err) { + iowrite32(tmp & regs->clic_out_err, + regs->outb_isr_cause); + } + } else { + if (tmp & (regs->clic_in_err | regs->clic_out_err)) + iowrite32(tmp & (regs->clic_in_err | + regs->clic_out_err), + regs->outb_isr_cause); + } + status ^= mhba->regs->int_comaerr; /* inbound or outbound parity error, command will timeout */ } - if (status & INT_MAP_COMAOUT) { - tmp = ioread32(regs + CLA_ISR_CAUSE); - if (tmp & CLIC_OUT_IRQ) - iowrite32(tmp & CLIC_OUT_IRQ, regs + CLA_ISR_CAUSE); + if (status & regs->int_comaout) { + tmp = ioread32(regs->outb_isr_cause); + if (tmp & regs->clic_irq) + iowrite32(tmp & regs->clic_irq, regs->outb_isr_cause); } - if (status & INT_MAP_DL_CPU2PCIEA) { - isr_status = ioread32(regs + CPU_ARM_TO_PCIEA_DRBL_REG); + if (status & regs->int_dl_cpu2pciea) { + isr_status = ioread32(regs->arm_to_pciea_drbl_reg); if (isr_status) - iowrite32(isr_status, regs + CPU_ARM_TO_PCIEA_DRBL_REG); + iowrite32(isr_status, regs->arm_to_pciea_drbl_reg); } mhba->global_isr = status; @@ -1464,24 +2006,38 @@ static int mvumi_clear_intr(void *extend) /** * mvumi_read_fw_status_reg - returns the current FW status value - * @regs: FW register set + * @mhba: Adapter soft state */ -static unsigned int mvumi_read_fw_status_reg(void *regs) +static unsigned int mvumi_read_fw_status_reg(struct mvumi_hba *mhba) { unsigned int status; - status = ioread32(regs + CPU_ARM_TO_PCIEA_DRBL_REG); + status = ioread32(mhba->regs->arm_to_pciea_drbl_reg); if (status) - iowrite32(status, regs + CPU_ARM_TO_PCIEA_DRBL_REG); + iowrite32(status, mhba->regs->arm_to_pciea_drbl_reg); return status; } -static struct mvumi_instance_template mvumi_instance_template = { +static struct mvumi_instance_template mvumi_instance_9143 = { .fire_cmd = mvumi_fire_cmd, .enable_intr = mvumi_enable_intr, .disable_intr = mvumi_disable_intr, .clear_intr = mvumi_clear_intr, .read_fw_status_reg = mvumi_read_fw_status_reg, + .check_ib_list = mvumi_check_ib_list_9143, + .check_ob_list = mvumi_check_ob_list_9143, + .reset_host = mvumi_reset_host_9143, +}; + +static struct mvumi_instance_template mvumi_instance_9580 = { + .fire_cmd = mvumi_fire_cmd, + .enable_intr = mvumi_enable_intr, + .disable_intr = mvumi_disable_intr, + .clear_intr = mvumi_clear_intr, + .read_fw_status_reg = mvumi_read_fw_status_reg, + .check_ib_list = mvumi_check_ib_list_9580, + .check_ob_list = mvumi_check_ob_list_9580, + .reset_host = mvumi_reset_host_9580, }; static int mvumi_slave_configure(struct scsi_device *sdev) @@ -1681,6 +2237,124 @@ static struct scsi_transport_template mvumi_transport_template = { .eh_timed_out = mvumi_timed_out, }; +static int mvumi_cfg_hw_reg(struct mvumi_hba *mhba) +{ + void *base = NULL; + struct mvumi_hw_regs *regs; + + switch (mhba->pdev->device) { + case PCI_DEVICE_ID_MARVELL_MV9143: + mhba->mmio = mhba->base_addr[0]; + base = mhba->mmio; + if (!mhba->regs) { + mhba->regs = kzalloc(sizeof(*regs), GFP_KERNEL); + if (mhba->regs == NULL) + return -ENOMEM; + } + regs = mhba->regs; + + /* For Arm */ + regs->ctrl_sts_reg = base + 0x20104; + regs->rstoutn_mask_reg = base + 0x20108; + regs->sys_soft_rst_reg = base + 0x2010C; + regs->main_int_cause_reg = base + 0x20200; + regs->enpointa_mask_reg = base + 0x2020C; + regs->rstoutn_en_reg = base + 0xF1400; + /* For Doorbell */ + regs->pciea_to_arm_drbl_reg = base + 0x20400; + regs->arm_to_pciea_drbl_reg = base + 0x20408; + regs->arm_to_pciea_mask_reg = base + 0x2040C; + regs->pciea_to_arm_msg0 = base + 0x20430; + regs->pciea_to_arm_msg1 = base + 0x20434; + regs->arm_to_pciea_msg0 = base + 0x20438; + regs->arm_to_pciea_msg1 = base + 0x2043C; + + /* For Message Unit */ + + regs->inb_aval_count_basel = base + 0x508; + regs->inb_aval_count_baseh = base + 0x50C; + regs->inb_write_pointer = base + 0x518; + regs->inb_read_pointer = base + 0x51C; + regs->outb_coal_cfg = base + 0x568; + regs->outb_copy_basel = base + 0x5B0; + regs->outb_copy_baseh = base + 0x5B4; + regs->outb_copy_pointer = base + 0x544; + regs->outb_read_pointer = base + 0x548; + regs->outb_isr_cause = base + 0x560; + regs->outb_coal_cfg = base + 0x568; + /* Bit setting for HW */ + regs->int_comaout = 1 << 8; + regs->int_comaerr = 1 << 6; + regs->int_dl_cpu2pciea = 1 << 1; + regs->cl_pointer_toggle = 1 << 12; + regs->clic_irq = 1 << 1; + regs->clic_in_err = 1 << 8; + regs->clic_out_err = 1 << 12; + regs->cl_slot_num_mask = 0xFFF; + regs->int_drbl_int_mask = 0x3FFFFFFF; + regs->int_mu = regs->int_dl_cpu2pciea | regs->int_comaout | + regs->int_comaerr; + break; + case PCI_DEVICE_ID_MARVELL_MV9580: + mhba->mmio = mhba->base_addr[2]; + base = mhba->mmio; + if (!mhba->regs) { + mhba->regs = kzalloc(sizeof(*regs), GFP_KERNEL); + if (mhba->regs == NULL) + return -ENOMEM; + } + regs = mhba->regs; + /* For Arm */ + regs->ctrl_sts_reg = base + 0x20104; + regs->rstoutn_mask_reg = base + 0x1010C; + regs->sys_soft_rst_reg = base + 0x10108; + regs->main_int_cause_reg = base + 0x10200; + regs->enpointa_mask_reg = base + 0x1020C; + regs->rstoutn_en_reg = base + 0xF1400; + + /* For Doorbell */ + regs->pciea_to_arm_drbl_reg = base + 0x10460; + regs->arm_to_pciea_drbl_reg = base + 0x10480; + regs->arm_to_pciea_mask_reg = base + 0x10484; + regs->pciea_to_arm_msg0 = base + 0x10400; + regs->pciea_to_arm_msg1 = base + 0x10404; + regs->arm_to_pciea_msg0 = base + 0x10420; + regs->arm_to_pciea_msg1 = base + 0x10424; + + /* For reset*/ + regs->reset_request = base + 0x10108; + regs->reset_enable = base + 0x1010c; + + /* For Message Unit */ + regs->inb_aval_count_basel = base + 0x4008; + regs->inb_aval_count_baseh = base + 0x400C; + regs->inb_write_pointer = base + 0x4018; + regs->inb_read_pointer = base + 0x401C; + regs->outb_copy_basel = base + 0x4058; + regs->outb_copy_baseh = base + 0x405C; + regs->outb_copy_pointer = base + 0x406C; + regs->outb_read_pointer = base + 0x4070; + regs->outb_coal_cfg = base + 0x4080; + regs->outb_isr_cause = base + 0x4088; + /* Bit setting for HW */ + regs->int_comaout = 1 << 4; + regs->int_dl_cpu2pciea = 1 << 12; + regs->int_comaerr = 1 << 29; + regs->cl_pointer_toggle = 1 << 14; + regs->cl_slot_num_mask = 0x3FFF; + regs->clic_irq = 1 << 0; + regs->clic_out_err = 1 << 1; + regs->int_drbl_int_mask = 0x3FFFFFFF; + regs->int_mu = regs->int_dl_cpu2pciea | regs->int_comaout; + break; + default: + return -1; + break; + } + + return 0; +} + /** * mvumi_init_fw - Initializes the FW * @mhba: Adapter soft state @@ -1699,15 +2373,18 @@ static int mvumi_init_fw(struct mvumi_hba *mhba) if (ret) goto fail_ioremap; - mhba->mmio = mhba->base_addr[0]; - switch (mhba->pdev->device) { case PCI_DEVICE_ID_MARVELL_MV9143: - mhba->instancet = &mvumi_instance_template; + mhba->instancet = &mvumi_instance_9143; mhba->io_seq = 0; mhba->max_sge = MVUMI_MAX_SG_ENTRY; mhba->request_id_enabled = 1; break; + case PCI_DEVICE_ID_MARVELL_MV9580: + mhba->instancet = &mvumi_instance_9580; + mhba->io_seq = 0; + mhba->max_sge = MVUMI_MAX_SG_ENTRY; + break; default: dev_err(&mhba->pdev->dev, "device 0x%x not supported!\n", mhba->pdev->device); @@ -1717,15 +2394,21 @@ static int mvumi_init_fw(struct mvumi_hba *mhba) } dev_dbg(&mhba->pdev->dev, "device id : %04X is found.\n", mhba->pdev->device); - - mhba->handshake_page = kzalloc(HSP_MAX_SIZE, GFP_KERNEL); + ret = mvumi_cfg_hw_reg(mhba); + if (ret) { + dev_err(&mhba->pdev->dev, + "failed to allocate memory for reg\n"); + ret = -ENOMEM; + goto fail_alloc_mem; + } + mhba->handshake_page = pci_alloc_consistent(mhba->pdev, HSP_MAX_SIZE, + &mhba->handshake_page_phys); if (!mhba->handshake_page) { dev_err(&mhba->pdev->dev, "failed to allocate memory for handshake\n"); ret = -ENOMEM; - goto fail_alloc_mem; + goto fail_alloc_page; } - mhba->handshake_page_phys = virt_to_phys(mhba->handshake_page); if (mvumi_start(mhba)) { ret = -EINVAL; @@ -1739,7 +2422,10 @@ static int mvumi_init_fw(struct mvumi_hba *mhba) fail_ready_state: mvumi_release_mem_resource(mhba); - kfree(mhba->handshake_page); + pci_free_consistent(mhba->pdev, HSP_MAX_SIZE, + mhba->handshake_page, mhba->handshake_page_phys); +fail_alloc_page: + kfree(mhba->regs); fail_alloc_mem: mvumi_unmap_pci_addr(mhba->pdev, mhba->base_addr); fail_ioremap: @@ -1755,6 +2441,7 @@ fail_ioremap: static int mvumi_io_attach(struct mvumi_hba *mhba) { struct Scsi_Host *host = mhba->shost; + struct scsi_device *sdev = NULL; int ret; unsigned int max_sg = (mhba->ib_max_size + 4 - sizeof(struct mvumi_msg_frame)) / sizeof(struct mvumi_sgl); @@ -1764,7 +2451,7 @@ static int mvumi_io_attach(struct mvumi_hba *mhba) host->can_queue = (mhba->max_io - 1) ? (mhba->max_io - 1) : 1; host->sg_tablesize = mhba->max_sge > max_sg ? max_sg : mhba->max_sge; host->max_sectors = mhba->max_transfer_size / 512; - host->cmd_per_lun = (mhba->max_io - 1) ? (mhba->max_io - 1) : 1; + host->cmd_per_lun = (mhba->max_io - 1) ? (mhba->max_io - 1) : 1; host->max_id = mhba->max_target_id; host->max_cmd_len = MAX_COMMAND_SIZE; host->transportt = &mvumi_transport_template; @@ -1775,9 +2462,43 @@ static int mvumi_io_attach(struct mvumi_hba *mhba) return ret; } mhba->fw_flag |= MVUMI_FW_ATTACH; - scsi_scan_host(host); + mutex_lock(&mhba->sas_discovery_mutex); + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9580) + ret = scsi_add_device(host, 0, mhba->max_target_id - 1, 0); + else + ret = 0; + if (ret) { + dev_err(&mhba->pdev->dev, "add virtual device failed\n"); + mutex_unlock(&mhba->sas_discovery_mutex); + goto fail_add_device; + } + + mhba->dm_thread = kthread_create(mvumi_rescan_bus, + mhba, "mvumi_scanthread"); + if (IS_ERR(mhba->dm_thread)) { + dev_err(&mhba->pdev->dev, + "failed to create device scan thread\n"); + mutex_unlock(&mhba->sas_discovery_mutex); + goto fail_create_thread; + } + atomic_set(&mhba->pnp_count, 1); + wake_up_process(mhba->dm_thread); + + mutex_unlock(&mhba->sas_discovery_mutex); return 0; + +fail_create_thread: + if (mhba->pdev->device == PCI_DEVICE_ID_MARVELL_MV9580) + sdev = scsi_device_lookup(mhba->shost, 0, + mhba->max_target_id - 1, 0); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } +fail_add_device: + scsi_remove_host(mhba->shost); + return ret; } /** @@ -1828,8 +2549,12 @@ static int __devinit mvumi_probe_one(struct pci_dev *pdev, INIT_LIST_HEAD(&mhba->free_ob_list); INIT_LIST_HEAD(&mhba->res_list); INIT_LIST_HEAD(&mhba->waiting_req_list); + mutex_init(&mhba->device_lock); + INIT_LIST_HEAD(&mhba->mhba_dev_list); + INIT_LIST_HEAD(&mhba->shost_dev_list); atomic_set(&mhba->fw_outstanding, 0); init_waitqueue_head(&mhba->int_cmd_wait_q); + mutex_init(&mhba->sas_discovery_mutex); mhba->pdev = pdev; mhba->shost = host; @@ -1845,19 +2570,22 @@ static int __devinit mvumi_probe_one(struct pci_dev *pdev, dev_err(&pdev->dev, "failed to register IRQ\n"); goto fail_init_irq; } - mhba->instancet->enable_intr(mhba->mmio); + + mhba->instancet->enable_intr(mhba); pci_set_drvdata(pdev, mhba); ret = mvumi_io_attach(mhba); if (ret) goto fail_io_attach; + + mvumi_backup_bar_addr(mhba); dev_dbg(&pdev->dev, "probe mvumi driver successfully.\n"); return 0; fail_io_attach: pci_set_drvdata(pdev, NULL); - mhba->instancet->disable_intr(mhba->mmio); + mhba->instancet->disable_intr(mhba); free_irq(mhba->pdev->irq, mhba); fail_init_irq: mvumi_release_fw(mhba); @@ -1877,11 +2605,17 @@ static void mvumi_detach_one(struct pci_dev *pdev) struct mvumi_hba *mhba; mhba = pci_get_drvdata(pdev); + if (mhba->dm_thread) { + kthread_stop(mhba->dm_thread); + mhba->dm_thread = NULL; + } + + mvumi_detach_devices(mhba); host = mhba->shost; scsi_remove_host(mhba->shost); mvumi_flush_cache(mhba); - mhba->instancet->disable_intr(mhba->mmio); + mhba->instancet->disable_intr(mhba); free_irq(mhba->pdev->irq, mhba); mvumi_release_fw(mhba); scsi_host_put(host); @@ -1909,7 +2643,7 @@ static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state) mvumi_flush_cache(mhba); pci_set_drvdata(pdev, mhba); - mhba->instancet->disable_intr(mhba->mmio); + mhba->instancet->disable_intr(mhba); free_irq(mhba->pdev->irq, mhba); mvumi_unmap_pci_addr(pdev, mhba->base_addr); pci_release_regions(pdev); @@ -1956,8 +2690,13 @@ static int mvumi_resume(struct pci_dev *pdev) if (ret) goto release_regions; + if (mvumi_cfg_hw_reg(mhba)) { + ret = -EINVAL; + goto unmap_pci_addr; + } + mhba->mmio = mhba->base_addr[0]; - mvumi_reset(mhba->mmio); + mvumi_reset(mhba); if (mvumi_start(mhba)) { ret = -EINVAL; @@ -1970,7 +2709,7 @@ static int mvumi_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "failed to register IRQ\n"); goto unmap_pci_addr; } - mhba->instancet->enable_intr(mhba->mmio); + mhba->instancet->enable_intr(mhba); return 0; diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h index 10b9237566f0..e360135fd1bd 100644 --- a/drivers/scsi/mvumi.h +++ b/drivers/scsi/mvumi.h @@ -34,51 +34,87 @@ #define MV_DRIVER_NAME "mvumi" #define PCI_VENDOR_ID_MARVELL_2 0x1b4b #define PCI_DEVICE_ID_MARVELL_MV9143 0x9143 +#define PCI_DEVICE_ID_MARVELL_MV9580 0x9580 #define MVUMI_INTERNAL_CMD_WAIT_TIME 45 +#define MVUMI_INQUIRY_LENGTH 44 +#define MVUMI_INQUIRY_UUID_OFF 36 +#define MVUMI_INQUIRY_UUID_LEN 8 #define IS_DMA64 (sizeof(dma_addr_t) == 8) enum mvumi_qc_result { - MV_QUEUE_COMMAND_RESULT_SENT = 0, + MV_QUEUE_COMMAND_RESULT_SENT = 0, MV_QUEUE_COMMAND_RESULT_NO_RESOURCE, }; -enum { - /*******************************************/ - - /* ARM Mbus Registers Map */ - - /*******************************************/ - CPU_MAIN_INT_CAUSE_REG = 0x20200, - CPU_MAIN_IRQ_MASK_REG = 0x20204, - CPU_MAIN_FIQ_MASK_REG = 0x20208, - CPU_ENPOINTA_MASK_REG = 0x2020C, - CPU_ENPOINTB_MASK_REG = 0x20210, - - INT_MAP_COMAERR = 1 << 6, - INT_MAP_COMAIN = 1 << 7, - INT_MAP_COMAOUT = 1 << 8, - INT_MAP_COMBERR = 1 << 9, - INT_MAP_COMBIN = 1 << 10, - INT_MAP_COMBOUT = 1 << 11, - - INT_MAP_COMAINT = (INT_MAP_COMAOUT | INT_MAP_COMAERR), - INT_MAP_COMBINT = (INT_MAP_COMBOUT | INT_MAP_COMBIN | INT_MAP_COMBERR), - - INT_MAP_DL_PCIEA2CPU = 1 << 0, - INT_MAP_DL_CPU2PCIEA = 1 << 1, - - /***************************************/ +struct mvumi_hw_regs { + /* For CPU */ + void *main_int_cause_reg; + void *enpointa_mask_reg; + void *enpointb_mask_reg; + void *rstoutn_en_reg; + void *ctrl_sts_reg; + void *rstoutn_mask_reg; + void *sys_soft_rst_reg; + + /* For Doorbell */ + void *pciea_to_arm_drbl_reg; + void *arm_to_pciea_drbl_reg; + void *arm_to_pciea_mask_reg; + void *pciea_to_arm_msg0; + void *pciea_to_arm_msg1; + void *arm_to_pciea_msg0; + void *arm_to_pciea_msg1; + + /* reset register */ + void *reset_request; + void *reset_enable; + + /* For Message Unit */ + void *inb_list_basel; + void *inb_list_baseh; + void *inb_aval_count_basel; + void *inb_aval_count_baseh; + void *inb_write_pointer; + void *inb_read_pointer; + void *outb_list_basel; + void *outb_list_baseh; + void *outb_copy_basel; + void *outb_copy_baseh; + void *outb_copy_pointer; + void *outb_read_pointer; + void *inb_isr_cause; + void *outb_isr_cause; + void *outb_coal_cfg; + void *outb_coal_timeout; + + /* Bit setting for HW */ + u32 int_comaout; + u32 int_comaerr; + u32 int_dl_cpu2pciea; + u32 int_mu; + u32 int_drbl_int_mask; + u32 int_main_int_mask; + u32 cl_pointer_toggle; + u32 cl_slot_num_mask; + u32 clic_irq; + u32 clic_in_err; + u32 clic_out_err; +}; - /* ARM Doorbell Registers Map */ +struct mvumi_dyn_list_entry { + u32 src_low_addr; + u32 src_high_addr; + u32 if_length; + u32 reserve; +}; - /***************************************/ - CPU_PCIEA_TO_ARM_DRBL_REG = 0x20400, - CPU_PCIEA_TO_ARM_MASK_REG = 0x20404, - CPU_ARM_TO_PCIEA_DRBL_REG = 0x20408, - CPU_ARM_TO_PCIEA_MASK_REG = 0x2040C, +#define SCSI_CMD_MARVELL_SPECIFIC 0xE1 +#define CDB_CORE_MODULE 0x1 +#define CDB_CORE_SHUTDOWN 0xB +enum { DRBL_HANDSHAKE = 1 << 0, DRBL_SOFT_RESET = 1 << 1, DRBL_BUS_CHANGE = 1 << 2, @@ -86,46 +122,6 @@ enum { DRBL_MU_RESET = 1 << 4, DRBL_HANDSHAKE_ISR = DRBL_HANDSHAKE, - CPU_PCIEA_TO_ARM_MSG0 = 0x20430, - CPU_PCIEA_TO_ARM_MSG1 = 0x20434, - CPU_ARM_TO_PCIEA_MSG0 = 0x20438, - CPU_ARM_TO_PCIEA_MSG1 = 0x2043C, - - /*******************************************/ - - /* ARM Communication List Registers Map */ - - /*******************************************/ - CLA_INB_LIST_BASEL = 0x500, - CLA_INB_LIST_BASEH = 0x504, - CLA_INB_AVAL_COUNT_BASEL = 0x508, - CLA_INB_AVAL_COUNT_BASEH = 0x50C, - CLA_INB_DESTI_LIST_BASEL = 0x510, - CLA_INB_DESTI_LIST_BASEH = 0x514, - CLA_INB_WRITE_POINTER = 0x518, - CLA_INB_READ_POINTER = 0x51C, - - CLA_OUTB_LIST_BASEL = 0x530, - CLA_OUTB_LIST_BASEH = 0x534, - CLA_OUTB_SOURCE_LIST_BASEL = 0x538, - CLA_OUTB_SOURCE_LIST_BASEH = 0x53C, - CLA_OUTB_COPY_POINTER = 0x544, - CLA_OUTB_READ_POINTER = 0x548, - - CLA_ISR_CAUSE = 0x560, - CLA_ISR_MASK = 0x564, - - INT_MAP_MU = (INT_MAP_DL_CPU2PCIEA | INT_MAP_COMAINT), - - CL_POINTER_TOGGLE = 1 << 12, - - CLIC_IN_IRQ = 1 << 0, - CLIC_OUT_IRQ = 1 << 1, - CLIC_IN_ERR_IRQ = 1 << 8, - CLIC_OUT_ERR_IRQ = 1 << 12, - - CL_SLOT_NUM_MASK = 0xFFF, - /* * Command flag is the flag for the CDB command itself */ @@ -137,15 +133,23 @@ enum { CMD_FLAG_DATA_IN = 1 << 3, /* 1-host write data */ CMD_FLAG_DATA_OUT = 1 << 4, - - SCSI_CMD_MARVELL_SPECIFIC = 0xE1, - CDB_CORE_SHUTDOWN = 0xB, + CMD_FLAG_PRDT_IN_HOST = 1 << 5, }; #define APICDB0_EVENT 0xF4 #define APICDB1_EVENT_GETEVENT 0 +#define APICDB1_HOST_GETEVENT 1 #define MAX_EVENTS_RETURNED 6 +#define DEVICE_OFFLINE 0 +#define DEVICE_ONLINE 1 + +struct mvumi_hotplug_event { + u16 size; + u8 dummy[2]; + u8 bitmap[0]; +}; + struct mvumi_driver_event { u32 time_stamp; u32 sequence_no; @@ -172,8 +176,14 @@ struct mvumi_events_wq { void *param; }; +#define HS_CAPABILITY_SUPPORT_COMPACT_SG (1U << 4) +#define HS_CAPABILITY_SUPPORT_PRD_HOST (1U << 5) +#define HS_CAPABILITY_SUPPORT_DYN_SRC (1U << 6) +#define HS_CAPABILITY_NEW_PAGE_IO_DEPTH_DEF (1U << 14) + #define MVUMI_MAX_SG_ENTRY 32 #define SGD_EOT (1L << 27) +#define SGD_EOT_CP (1L << 22) struct mvumi_sgl { u32 baseaddr_l; @@ -181,6 +191,39 @@ struct mvumi_sgl { u32 flags; u32 size; }; +struct mvumi_compact_sgl { + u32 baseaddr_l; + u32 baseaddr_h; + u32 flags; +}; + +#define GET_COMPACT_SGD_SIZE(sgd) \ + ((((struct mvumi_compact_sgl *)(sgd))->flags) & 0x3FFFFFL) + +#define SET_COMPACT_SGD_SIZE(sgd, sz) do { \ + (((struct mvumi_compact_sgl *)(sgd))->flags) &= ~0x3FFFFFL; \ + (((struct mvumi_compact_sgl *)(sgd))->flags) |= (sz); \ +} while (0) +#define sgd_getsz(_mhba, sgd, sz) do { \ + if (_mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG) \ + (sz) = GET_COMPACT_SGD_SIZE(sgd); \ + else \ + (sz) = (sgd)->size; \ +} while (0) + +#define sgd_setsz(_mhba, sgd, sz) do { \ + if (_mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG) \ + SET_COMPACT_SGD_SIZE(sgd, sz); \ + else \ + (sgd)->size = (sz); \ +} while (0) + +#define sgd_inc(_mhba, sgd) do { \ + if (_mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG) \ + sgd = (struct mvumi_sgl *)(((unsigned char *) (sgd)) + 12); \ + else \ + sgd = (struct mvumi_sgl *)(((unsigned char *) (sgd)) + 16); \ +} while (0) struct mvumi_res { struct list_head entry; @@ -197,7 +240,7 @@ enum resource_type { }; struct mvumi_sense_data { - u8 error_eode:7; + u8 error_code:7; u8 valid:1; u8 segment_number; u8 sense_key:4; @@ -220,6 +263,7 @@ struct mvumi_sense_data { struct mvumi_cmd { struct list_head queue_pointer; struct mvumi_msg_frame *frame; + dma_addr_t frame_phys; struct scsi_cmnd *scmd; atomic_t sync_cmd; void *data_buf; @@ -393,7 +437,8 @@ struct mvumi_hs_page2 { u16 frame_length; u8 host_type; - u8 reserved[3]; + u8 host_cap; + u8 reserved[2]; struct version_info host_ver; u32 system_io_bus; u32 slot_number; @@ -435,8 +480,17 @@ struct mvumi_tag { unsigned short size; }; +struct mvumi_device { + struct list_head list; + struct scsi_device *sdev; + u64 wwid; + u8 dev_type; + int id; +}; + struct mvumi_hba { void *base_addr[MAX_BASE_ADDRESS]; + u32 pci_base[MAX_BASE_ADDRESS]; void *mmio; struct list_head cmd_pool; struct Scsi_Host *shost; @@ -449,6 +503,9 @@ struct mvumi_hba { void *ib_list; dma_addr_t ib_list_phys; + void *ib_frame; + dma_addr_t ib_frame_phys; + void *ob_list; dma_addr_t ob_list_phys; @@ -477,12 +534,14 @@ struct mvumi_hba { unsigned char hba_total_pages; unsigned char fw_flag; unsigned char request_id_enabled; + unsigned char eot_flag; unsigned short hba_capability; unsigned short io_seq; unsigned int ib_cur_slot; unsigned int ob_cur_slot; unsigned int fw_state; + struct mutex sas_discovery_mutex; struct list_head ob_data_list; struct list_head free_ob_list; @@ -491,14 +550,24 @@ struct mvumi_hba { struct mvumi_tag tag_pool; struct mvumi_cmd **tag_cmd; + struct mvumi_hw_regs *regs; + struct mutex device_lock; + struct list_head mhba_dev_list; + struct list_head shost_dev_list; + struct task_struct *dm_thread; + atomic_t pnp_count; }; struct mvumi_instance_template { - void (*fire_cmd)(struct mvumi_hba *, struct mvumi_cmd *); - void (*enable_intr)(void *) ; - void (*disable_intr)(void *); - int (*clear_intr)(void *); - unsigned int (*read_fw_status_reg)(void *); + void (*fire_cmd) (struct mvumi_hba *, struct mvumi_cmd *); + void (*enable_intr) (struct mvumi_hba *); + void (*disable_intr) (struct mvumi_hba *); + int (*clear_intr) (void *); + unsigned int (*read_fw_status_reg) (struct mvumi_hba *); + unsigned int (*check_ib_list) (struct mvumi_hba *); + int (*check_ob_list) (struct mvumi_hba *, unsigned int *, + unsigned int *); + int (*reset_host) (struct mvumi_hba *); }; extern struct timezone sys_tz; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 799a58bb9859..48fca47384b7 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2080,6 +2080,7 @@ qla2x00_configure_hba(scsi_qla_host_t *vha) uint8_t domain; char connect_type[22]; struct qla_hw_data *ha = vha->hw; + unsigned long flags; /* Get host addresses. */ rval = qla2x00_get_adapter_id(vha, @@ -2154,9 +2155,9 @@ 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); + spin_lock_irqsave(&ha->vport_slock, flags); qlt_update_vp_map(vha, SET_AL_PA); - spin_unlock(&ha->vport_slock); + spin_unlock_irqrestore(&ha->vport_slock, flags); if (!vha->flags.init_done) ql_log(ql_log_info, vha, 0x2010, diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 57fbd5a3d4e2..5cda11c07c68 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2055,7 +2055,7 @@ static void unmap_region(sector_t lba, unsigned int len) block = lba + alignment; rem = do_div(block, granularity); - if (rem == 0 && lba + granularity <= end && block < map_size) { + if (rem == 0 && lba + granularity < end && block < map_size) { clear_bit(block, map_storep); if (scsi_debug_lbprz) memset(fake_storep + diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index de2337f255a7..c1b05a83d403 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -789,7 +789,6 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes) { struct scsi_device *sdev = scmd->device; - struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); struct Scsi_Host *shost = sdev->host; DECLARE_COMPLETION_ONSTACK(done); unsigned long timeleft; @@ -845,8 +844,11 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, scsi_eh_restore_cmnd(scmd, &ses); - if (sdrv && sdrv->eh_action) - rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); + if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); + if (sdrv->eh_action) + rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); + } return rtn; } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 528d52beaa1c..01440782feb2 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1221,7 +1221,12 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) /* * At this point, all outstanding requests in the adapter * should have been flushed out and return to us + * There is a potential race here where the host may be in + * the process of responding when we return from here. + * Just wait for all in-transit packets to be accounted for + * before we return from here. */ + storvsc_wait_to_drain(stor_device); return SUCCESS; } diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 3e79a2f00042..595af1ae4421 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -219,7 +219,7 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi, struct scatterlist sg; unsigned long flags; - sg_set_buf(&sg, &event_node->event, sizeof(struct virtio_scsi_event)); + sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event)); spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags); @@ -279,6 +279,31 @@ static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi, } } +static void virtscsi_handle_param_change(struct virtio_scsi *vscsi, + struct virtio_scsi_event *event) +{ + struct scsi_device *sdev; + struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); + unsigned int target = event->lun[1]; + unsigned int lun = (event->lun[2] << 8) | event->lun[3]; + u8 asc = event->reason & 255; + u8 ascq = event->reason >> 8; + + sdev = scsi_device_lookup(shost, 0, target, lun); + if (!sdev) { + pr_err("SCSI device %d 0 %d %d not found\n", + shost->host_no, target, lun); + return; + } + + /* Handle "Parameters changed", "Mode parameters changed", and + "Capacity data has changed". */ + if (asc == 0x2a && (ascq == 0x00 || ascq == 0x01 || ascq == 0x09)) + scsi_rescan_device(&sdev->sdev_gendev); + + scsi_device_put(sdev); +} + static void virtscsi_handle_event(struct work_struct *work) { struct virtio_scsi_event_node *event_node = @@ -297,6 +322,9 @@ static void virtscsi_handle_event(struct work_struct *work) case VIRTIO_SCSI_T_TRANSPORT_RESET: virtscsi_handle_transport_reset(vscsi, event); break; + case VIRTIO_SCSI_T_PARAM_CHANGE: + virtscsi_handle_param_change(vscsi, event); + break; default: pr_err("Unsupport virtio scsi event %x\n", event->event); } @@ -677,7 +705,11 @@ static int __devinit virtscsi_probe(struct virtio_device *vdev) cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1; shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue); shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF; - shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1; + + /* LUNs > 256 are reported with format 1, so they go in the range + * 16640-32767. + */ + shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1 + 0x4000; shost->max_id = num_targets; shost->max_channel = 0; shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; @@ -733,7 +765,8 @@ static struct virtio_device_id id_table[] = { }; static unsigned int features[] = { - VIRTIO_SCSI_F_HOTPLUG + VIRTIO_SCSI_F_HOTPLUG, + VIRTIO_SCSI_F_CHANGE, }; static struct virtio_driver virtio_scsi_driver = { diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 2ec5264dd002..ebdb0b676737 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -106,7 +106,8 @@ static void dump_video_chains(void) for (i = 0; i < omap_dss_get_num_overlays(); i++) { struct omap_overlay *ovl = omap_dss_get_overlay(i); struct omap_overlay_manager *mgr = ovl->manager; - struct omap_dss_device *dssdev = mgr ? mgr->device : NULL; + struct omap_dss_device *dssdev = mgr ? + mgr->get_device(mgr) : NULL; if (dssdev) { DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, dssdev->name); @@ -185,7 +186,7 @@ static int create_connector(struct drm_device *dev, for (j = 0; j < priv->num_encoders; j++) { struct omap_overlay_manager *mgr = omap_encoder_get_manager(priv->encoders[j]); - if (mgr->device == dssdev) { + if (mgr->get_device(mgr) == dssdev) { drm_mode_connector_attach_encoder(connector, priv->encoders[j]); } diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 2944ff88fdc0..f4abfe238f98 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -478,7 +478,6 @@ static void xencons_backend_changed(struct xenbus_device *dev, case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateInitWait: @@ -488,6 +487,10 @@ static void xencons_backend_changed(struct xenbus_device *dev, xenbus_switch_state(dev, XenbusStateConnected); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 36f2be4def2f..981f2132d128 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1551,6 +1551,9 @@ static const struct usb_device_id acm_ids[] = { Maybe we should define a new quirk for this. */ }, + { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ + .driver_info = NO_UNION_NORMAL, + }, { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ }, diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 20c33c42600a..d08d7998a4aa 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2139,21 +2139,6 @@ config FB_UDL mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. To compile as a module, choose M here: the module name is udlfb. -config FB_PNX4008_DUM - tristate "Display Update Module support on Philips PNX4008 board" - depends on FB && ARCH_PNX4008 - ---help--- - Say Y here to enable support for PNX4008 Display Update Module (DUM) - -config FB_PNX4008_DUM_RGB - tristate "RGB Framebuffer support on Philips PNX4008 board" - depends on FB_PNX4008_DUM - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here to enable support for PNX4008 RGB Framebuffer - config FB_IBM_GXT4500 tristate "Framebuffer support for IBM GXT4500P adaptor" depends on FB && PPC diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 194035986af2..23e948ebfab8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -127,8 +127,6 @@ obj-$(CONFIG_FB_S3C) += s3c-fb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o -obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ -obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 887df9d81422..7fa1bf823729 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -949,7 +949,6 @@ static int round_down_bpp = 1; /* for mode probing */ static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ -static int amifb_inverse = 0; static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ @@ -2355,7 +2354,6 @@ static int __init amifb_setup(char *options) if (!*this_opt) continue; if (!strcmp(this_opt, "inverse")) { - amifb_inverse = 1; fb_invert_cmaps(); } else if (!strcmp(this_opt, "ilbm")) amifb_ilbm = 1; diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index a1d58e9d3073..4659d5da6ff8 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -552,6 +552,7 @@ static int __devinit arcfb_probe(struct platform_device *dev) "arcfb", info)) { printk(KERN_INFO "arcfb: Failed req IRQ %d\n", par->irq); + retval = -EBUSY; goto err1; } } diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 15055395cd95..94cac9f9919f 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -931,8 +931,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) } info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); - if (!info->screen_base) + if (!info->screen_base) { + ret = -ENOMEM; goto release_intmem; + } /* * Don't clear the framebuffer -- someone may have set @@ -960,6 +962,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); if (!sinfo->mmio) { dev_err(dev, "cannot map LCDC registers\n"); + ret = -ENOMEM; goto release_mem; } diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c index befbc80d11fc..7347aa1e5e4a 100644 --- a/drivers/video/bf537-lq035.c +++ b/drivers/video/bf537-lq035.c @@ -760,18 +760,20 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) bfin_lq035_fb.flags = FBINFO_DEFAULT; - bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); + bfin_lq035_fb.pseudo_palette = devm_kzalloc(&pdev->dev, + sizeof(u32) * 16, + GFP_KERNEL); if (bfin_lq035_fb.pseudo_palette == NULL) { pr_err("failed to allocate pseudo_palette\n"); ret = -ENOMEM; - goto out_palette; + goto out_table; } if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) { pr_err("failed to allocate colormap (%d entries)\n", NBR_PALETTE); ret = -EFAULT; - goto out_cmap; + goto out_table; } if (register_framebuffer(&bfin_lq035_fb) < 0) { @@ -804,9 +806,6 @@ out_lcd: unregister_framebuffer(&bfin_lq035_fb); out_reg: fb_dealloc_cmap(&bfin_lq035_fb.cmap); -out_cmap: - kfree(bfin_lq035_fb.pseudo_palette); -out_palette: out_table: dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); fb_buffer = NULL; @@ -834,7 +833,6 @@ static int __devexit bfin_lq035_remove(struct platform_device *pdev) free_dma(CH_PPI); - kfree(bfin_lq035_fb.pseudo_palette); fb_dealloc_cmap(&bfin_lq035_fb.cmap); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index dc2f0047769b..ff5663f5c64f 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -525,6 +525,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; info->dev = &pdev->dev; + spin_lock_init(&info->lock); platform_set_drvdata(pdev, fbinfo); @@ -601,7 +602,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) fbinfo->fbops = &bfin_bf54x_fb_ops; - fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); + fbinfo->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16, + GFP_KERNEL); if (!fbinfo->pseudo_palette) { printk(KERN_ERR DRIVER_NAME "Fail to allocate pseudo_palette\n"); @@ -616,7 +618,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) "Fail to allocate colormap (%d entries)\n", BFIN_LCD_NBR_PALETTE_ENTRIES); ret = -EFAULT; - goto out5; + goto out4; } if (request_ports(info)) { @@ -671,8 +673,6 @@ out7: free_ports(info); out6: fb_dealloc_cmap(&fbinfo->cmap); -out5: - kfree(fbinfo->pseudo_palette); out4: dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, info->dma_handle); @@ -699,7 +699,6 @@ static int __devexit bfin_bf54x_remove(struct platform_device *pdev) dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, info->dma_handle); - kfree(fbinfo->pseudo_palette); fb_dealloc_cmap(&fbinfo->cmap); #ifndef NO_BL_SUPPORT diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index 353c02fe8a95..6fbc75c2f0a1 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c @@ -577,6 +577,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; info->dev = &pdev->dev; + spin_lock_init(&info->lock); info->disp_info = pdev->dev.platform_data; @@ -853,17 +854,7 @@ static struct platform_driver bfin_lq035q1_driver = { }, }; -static int __init bfin_lq035q1_driver_init(void) -{ - return platform_driver_register(&bfin_lq035q1_driver); -} -module_init(bfin_lq035q1_driver_init); - -static void __exit bfin_lq035q1_driver_cleanup(void) -{ - platform_driver_unregister(&bfin_lq035q1_driver); -} -module_exit(bfin_lq035q1_driver_cleanup); +module_platform_driver(bfin_lq035q1_driver); MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 7a0c05f3537e..ae0fb24b8b43 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -447,6 +447,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; info->dev = &pdev->dev; + spin_lock_init(&info->lock); platform_set_drvdata(pdev, fbinfo); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 7ba74cd4be61..6bea9a936798 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -319,8 +319,10 @@ static int __devinit bw2_probe(struct platform_device *op) info->screen_base = of_ioremap(&op->resource[0], 0, info->fix.smem_len, "bw2 ram"); - if (!info->screen_base) + if (!info->screen_base) { + err = -ENOMEM; goto out_unmap_regs; + } bw2_blank(FB_BLANK_UNBLANK, info); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index f927a7b1a8d4..c5e7612ff876 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -398,7 +398,8 @@ static int __devinit cg3_probe(struct platform_device *op) goto out_unmap_screen; } - if (fb_alloc_cmap(&info->cmap, 256, 0)) + err = fb_alloc_cmap(&info->cmap, 256, 0); + if (err) goto out_unmap_screen; fb_set_cmap(&info->cmap, info); diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index eae46f6457e2..01a4ee7cc6b1 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c @@ -348,7 +348,8 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev) } info->screen_size = resource_size(res); - info->screen_base = ioremap(res->start, info->screen_size); + info->screen_base = devm_ioremap(&dev->dev, res->start, + info->screen_size); info->fbops = &cobalt_lcd_fbops; info->fix = cobalt_lcdfb_fix; info->fix.smem_start = res->start; @@ -359,7 +360,6 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev) retval = register_framebuffer(info); if (retval < 0) { - iounmap(info->screen_base); framebuffer_release(info); return retval; } @@ -380,7 +380,6 @@ static int __devexit cobalt_lcdfb_remove(struct platform_device *dev) info = platform_get_drvdata(dev); if (info) { - iounmap(info->screen_base); unregister_framebuffer(info); framebuffer_release(info); } diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index fa6e698e63c4..838caa1cfef7 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c @@ -1092,7 +1092,7 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = { /*{*/ /* Char 124: '|' */ 0x44, /*= [ * ] */ 0x44, /*= [ * ] */ - 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ 0x44, /*= [ * ] */ 0x44, /*= [ * ] */ 0x00, /*= [ ] */ diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c index 5abf290c6eb7..268151325b83 100644 --- a/drivers/video/console/font_sun8x16.c +++ b/drivers/video/console/font_sun8x16.c @@ -127,7 +127,7 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = { /*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00, /*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00, /*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00, -/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, /*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, /*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00, diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index c1527f5b47ee..e40125cb313e 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1804,8 +1804,10 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) cfb->irq = dev->irq; cfb->region = pci_ioremap_bar(dev, 0); - if (!cfb->region) + if (!cfb->region) { + err = -ENOMEM; goto failed_ioremap; + } cfb->regs = cfb->region + MMIO_OFFSET; cfb->fb.device = &dev->dev; diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 113d43a16f54..80665f66ac1a 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -26,7 +26,9 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/uaccess.h> +#include <linux/pm_runtime.h> #include <linux/interrupt.h> +#include <linux/wait.h> #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/console.h> @@ -48,6 +50,7 @@ #define LCD_PL_LOAD_DONE BIT(6) #define LCD_FIFO_UNDERFLOW BIT(5) #define LCD_SYNC_LOST BIT(2) +#define LCD_FRAME_DONE BIT(0) /* LCD DMA Control Register */ #define LCD_DMA_BURST_SIZE(x) ((x) << 4) @@ -86,6 +89,8 @@ #define LCD_V2_LIDD_CLK_EN BIT(1) #define LCD_V2_CORE_CLK_EN BIT(0) #define LCD_V2_LPP_B10 26 +#define LCD_V2_TFT_24BPP_MODE BIT(25) +#define LCD_V2_TFT_24BPP_UNPACK BIT(26) /* LCD Raster Timing 2 Register */ #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) @@ -135,6 +140,8 @@ static void __iomem *da8xx_fb_reg_base; static struct resource *lcdc_regs; static unsigned int lcd_revision; static irq_handler_t lcdc_irq_handler; +static wait_queue_head_t frame_done_wq; +static int frame_done_flag; static inline unsigned int lcdc_read(unsigned int addr) { @@ -156,7 +163,6 @@ struct da8xx_fb_par { unsigned int dma_end; struct clk *lcdc_clk; int irq; - unsigned short pseudo_palette[16]; unsigned int palette_sz; unsigned int pxl_clk; int blank; @@ -175,6 +181,7 @@ struct da8xx_fb_par { unsigned int lcd_fck_rate; #endif void (*panel_power_ctrl)(int); + u32 pseudo_palette[16]; }; /* Variable Screen Information */ @@ -288,13 +295,26 @@ static inline void lcd_enable_raster(void) } /* Disable the Raster Engine of the LCD Controller */ -static inline void lcd_disable_raster(void) +static inline void lcd_disable_raster(bool wait_for_frame_done) { u32 reg; + int ret; reg = lcdc_read(LCD_RASTER_CTRL_REG); if (reg & LCD_RASTER_ENABLE) lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + else + /* return if already disabled */ + return; + + if ((wait_for_frame_done == true) && (lcd_revision == LCD_VERSION_2)) { + frame_done_flag = 0; + ret = wait_event_interruptible_timeout(frame_done_wq, + frame_done_flag != 0, + msecs_to_jiffies(50)); + if (ret == 0) + pr_err("LCD Controller timed out\n"); + } } static void lcd_blit(int load_mode, struct da8xx_fb_par *par) @@ -321,7 +341,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) } else { reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | LCD_V2_END_OF_FRAME0_INT_ENA | - LCD_V2_END_OF_FRAME1_INT_ENA; + LCD_V2_END_OF_FRAME1_INT_ENA | + LCD_FRAME_DONE; lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); } reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; @@ -499,6 +520,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, { u32 reg; + if (bpp > 16 && lcd_revision == LCD_VERSION_1) + return -EINVAL; + /* Set the Panel Width */ /* Pixels per line = (PPL + 1)*16 */ if (lcd_revision == LCD_VERSION_1) { @@ -542,14 +566,19 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); if (raster_order) reg |= LCD_RASTER_ORDER; - lcdc_write(reg, LCD_RASTER_CTRL_REG); + + par->palette_sz = 16 * 2; switch (bpp) { case 1: case 2: case 4: case 16: - par->palette_sz = 16 * 2; + break; + case 24: + reg |= LCD_V2_TFT_24BPP_MODE; + case 32: + reg |= LCD_V2_TFT_24BPP_UNPACK; break; case 8: @@ -560,9 +589,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, return -EINVAL; } + lcdc_write(reg, LCD_RASTER_CTRL_REG); + return 0; } +#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -578,13 +610,38 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) return 1; - if (info->var.bits_per_pixel == 4) { - if (regno > 15) - return 1; + if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) + return -EINVAL; - if (info->var.grayscale) { - pal = regno; - } else { + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + break; + case FB_VISUAL_PSEUDOCOLOR: + switch (info->var.bits_per_pixel) { + case 4: + if (regno > 15) + return -EINVAL; + + if (info->var.grayscale) { + pal = regno; + } else { + red >>= 4; + green >>= 8; + blue >>= 12; + + pal = red & 0x0f00; + pal |= green & 0x00f0; + pal |= blue & 0x000f; + } + if (regno == 0) + pal |= 0x2000; + palette[regno] = pal; + break; + + case 8: red >>= 4; green >>= 8; blue >>= 12; @@ -592,36 +649,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, pal = (red & 0x0f00); pal |= (green & 0x00f0); pal |= (blue & 0x000f); - } - if (regno == 0) - pal |= 0x2000; - palette[regno] = pal; - - } else if (info->var.bits_per_pixel == 8) { - red >>= 4; - green >>= 8; - blue >>= 12; - - pal = (red & 0x0f00); - pal |= (green & 0x00f0); - pal |= (blue & 0x000f); - if (palette[regno] != pal) { - update_hw = 1; - palette[regno] = pal; + if (palette[regno] != pal) { + update_hw = 1; + palette[regno] = pal; + } + break; } - } else if ((info->var.bits_per_pixel == 16) && regno < 16) { - red >>= (16 - info->var.red.length); - red <<= info->var.red.offset; + break; + } - green >>= (16 - info->var.green.length); - green <<= info->var.green.offset; + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; - blue >>= (16 - info->var.blue.length); - blue <<= info->var.blue.offset; + if (regno > 15) + return -EINVAL; - par->pseudo_palette[regno] = red | green | blue; + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + switch (info->var.bits_per_pixel) { + case 16: + ((u16 *) (info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + } if (palette[0] != 0x4000) { update_hw = 1; palette[0] = 0x4000; @@ -634,11 +691,12 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +#undef CNVT_TOHW static void lcd_reset(struct da8xx_fb_par *par) { /* Disable the Raster if previously Enabled */ - lcd_disable_raster(); + lcd_disable_raster(false); /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); @@ -734,7 +792,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) u32 stat = lcdc_read(LCD_MASKED_STAT_REG); if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_MASKED_STAT_REG); lcd_enable_raster(); } else if (stat & LCD_PL_LOAD_DONE) { @@ -744,7 +802,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) * interrupt via the following write to the status register. If * this is done after then one gets multiple PL done interrupts. */ - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_MASKED_STAT_REG); @@ -775,6 +833,14 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) par->vsync_flag = 1; wake_up_interruptible(&par->vsync_wait); } + + /* Set only when controller is disabled and at the end of + * active frame + */ + if (stat & BIT(0)) { + frame_done_flag = 1; + wake_up_interruptible(&frame_done_wq); + } } lcdc_write(0, LCD_END_OF_INT_IND_REG); @@ -789,7 +855,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) u32 reg_ras; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_STAT_REG); lcd_enable_raster(); } else if (stat & LCD_PL_LOAD_DONE) { @@ -799,7 +865,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) * interrupt via the following write to the status register. If * this is done after then one gets multiple PL done interrupts. */ - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_STAT_REG); @@ -842,6 +908,9 @@ static int fb_check_var(struct fb_var_screeninfo *var, { int err = 0; + if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) + return -EINVAL; + switch (var->bits_per_pixel) { case 1: case 8: @@ -877,6 +946,26 @@ static int fb_check_var(struct fb_var_screeninfo *var, var->transp.length = 0; var->nonstd = 0; break; + case 24: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->nonstd = 0; + break; + case 32: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->nonstd = 0; + break; default: err = -EINVAL; } @@ -898,9 +987,10 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, if (val == CPUFREQ_POSTCHANGE) { if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) { par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); - lcd_disable_raster(); + lcd_disable_raster(true); lcd_calc_clk_divider(par); - lcd_enable_raster(); + if (par->blank == FB_BLANK_UNBLANK) + lcd_enable_raster(); } } @@ -935,7 +1025,7 @@ static int __devexit fb_remove(struct platform_device *dev) if (par->panel_power_ctrl) par->panel_power_ctrl(0); - lcd_disable_raster(); + lcd_disable_raster(true); lcdc_write(0, LCD_RASTER_CTRL_REG); /* disable DMA */ @@ -948,8 +1038,8 @@ static int __devexit fb_remove(struct platform_device *dev) dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); free_irq(par->irq, par); - clk_disable(par->lcdc_clk); - clk_put(par->lcdc_clk); + pm_runtime_put_sync(&dev->dev); + pm_runtime_disable(&dev->dev); framebuffer_release(info); iounmap(da8xx_fb_reg_base); release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); @@ -1051,7 +1141,7 @@ static int cfb_blank(int blank, struct fb_info *info) if (par->panel_power_ctrl) par->panel_power_ctrl(0); - lcd_disable_raster(); + lcd_disable_raster(true); break; default: ret = -EINVAL; @@ -1183,9 +1273,9 @@ static int __devinit fb_probe(struct platform_device *device) ret = -ENODEV; goto err_ioremap; } - ret = clk_enable(fb_clk); - if (ret) - goto err_clk_put; + + pm_runtime_enable(&device->dev); + pm_runtime_get_sync(&device->dev); /* Determine LCD IP Version */ switch (lcdc_read(LCD_PID_REG)) { @@ -1213,7 +1303,7 @@ static int __devinit fb_probe(struct platform_device *device) if (i == ARRAY_SIZE(known_lcd_panels)) { dev_err(&device->dev, "GLCD: No valid panel found\n"); ret = -ENODEV; - goto err_clk_disable; + goto err_pm_runtime_disable; } else dev_info(&device->dev, "GLCD: Found %s panel\n", fb_pdata->type); @@ -1225,7 +1315,7 @@ static int __devinit fb_probe(struct platform_device *device) if (!da8xx_fb_info) { dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); ret = -ENOMEM; - goto err_clk_disable; + goto err_pm_runtime_disable; } par = da8xx_fb_info->par; @@ -1356,8 +1446,10 @@ static int __devinit fb_probe(struct platform_device *device) if (lcd_revision == LCD_VERSION_1) lcdc_irq_handler = lcdc_irq_handler_rev01; - else + else { + init_waitqueue_head(&frame_done_wq); lcdc_irq_handler = lcdc_irq_handler_rev02; + } ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); @@ -1385,11 +1477,9 @@ err_release_fb_mem: err_release_fb: framebuffer_release(da8xx_fb_info); -err_clk_disable: - clk_disable(fb_clk); - -err_clk_put: - clk_put(fb_clk); +err_pm_runtime_disable: + pm_runtime_put_sync(&device->dev); + pm_runtime_disable(&device->dev); err_ioremap: iounmap(da8xx_fb_reg_base); @@ -1401,6 +1491,69 @@ err_request_mem: } #ifdef CONFIG_PM +struct lcdc_context { + u32 clk_enable; + u32 ctrl; + u32 dma_ctrl; + u32 raster_timing_0; + u32 raster_timing_1; + u32 raster_timing_2; + u32 int_enable_set; + u32 dma_frm_buf_base_addr_0; + u32 dma_frm_buf_ceiling_addr_0; + u32 dma_frm_buf_base_addr_1; + u32 dma_frm_buf_ceiling_addr_1; + u32 raster_ctrl; +} reg_context; + +static void lcd_context_save(void) +{ + if (lcd_revision == LCD_VERSION_2) { + reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG); + reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG); + } + + reg_context.ctrl = lcdc_read(LCD_CTRL_REG); + reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG); + reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG); + reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG); + reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG); + reg_context.dma_frm_buf_base_addr_0 = + lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + reg_context.dma_frm_buf_ceiling_addr_0 = + lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + reg_context.dma_frm_buf_base_addr_1 = + lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + reg_context.dma_frm_buf_ceiling_addr_1 = + lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG); + return; +} + +static void lcd_context_restore(void) +{ + if (lcd_revision == LCD_VERSION_2) { + lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG); + lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG); + } + + lcdc_write(reg_context.ctrl, LCD_CTRL_REG); + lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG); + lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG); + lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG); + lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG); + lcdc_write(reg_context.dma_frm_buf_base_addr_0, + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0, + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + lcdc_write(reg_context.dma_frm_buf_base_addr_1, + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1, + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG); + return; +} + static int fb_suspend(struct platform_device *dev, pm_message_t state) { struct fb_info *info = platform_get_drvdata(dev); @@ -1411,8 +1564,9 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state) par->panel_power_ctrl(0); fb_set_suspend(info, 1); - lcd_disable_raster(); - clk_disable(par->lcdc_clk); + lcd_disable_raster(true); + lcd_context_save(); + pm_runtime_put_sync(&dev->dev); console_unlock(); return 0; @@ -1423,11 +1577,14 @@ static int fb_resume(struct platform_device *dev) struct da8xx_fb_par *par = info->par; console_lock(); - clk_enable(par->lcdc_clk); - lcd_enable_raster(); + pm_runtime_get_sync(&dev->dev); + lcd_context_restore(); + if (par->blank == FB_BLANK_UNBLANK) { + lcd_enable_raster(); - if (par->panel_power_ctrl) - par->panel_power_ctrl(1); + if (par->panel_power_ctrl) + par->panel_power_ctrl(1); + } fb_set_suspend(info, 0); console_unlock(); diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index f2c092da84b0..755ef3e65caf 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -529,7 +529,8 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) * any of the framebuffer registers. */ fbi->res = res; - fbi->mmio_base = ioremap(res->start, resource_size(res)); + fbi->mmio_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!fbi->mmio_base) { err = -ENXIO; goto failed_resource; @@ -553,20 +554,20 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) if (err == 0) { dev_err(info->dev, "No suitable video mode found\n"); err = -EINVAL; - goto failed_mode; + goto failed_resource; } if (mach_info->setup) { err = mach_info->setup(pdev); if (err) - goto failed_mode; + goto failed_resource; } err = ep93xxfb_check_var(&info->var, info); if (err) goto failed_check; - fbi->clk = clk_get(info->dev, NULL); + fbi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(fbi->clk)) { err = PTR_ERR(fbi->clk); fbi->clk = NULL; @@ -578,19 +579,15 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) err = register_framebuffer(info); if (err) - goto failed; + goto failed_check; dev_info(info->dev, "registered. Mode = %dx%d-%d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); return 0; -failed: - clk_put(fbi->clk); failed_check: if (fbi->mach_info->teardown) fbi->mach_info->teardown(pdev); -failed_mode: - iounmap(fbi->mmio_base); failed_resource: ep93xxfb_dealloc_videomem(info); failed_videomem: @@ -609,8 +606,6 @@ static int __devexit ep93xxfb_remove(struct platform_device *pdev) unregister_framebuffer(info); clk_disable(fbi->clk); - clk_put(fbi->clk); - iounmap(fbi->mmio_base); ep93xxfb_dealloc_videomem(info); fb_dealloc_cmap(&info->cmap); diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index c6c016a506ce..d55470e75412 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c @@ -29,6 +29,9 @@ static int exynos_dp_init_dp(struct exynos_dp_device *dp) exynos_dp_swreset(dp); + exynos_dp_init_analog_param(dp); + exynos_dp_init_interrupt(dp); + /* SW defined function Normal operation */ exynos_dp_enable_sw_function(dp); @@ -260,7 +263,7 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, static void exynos_dp_link_start(struct exynos_dp_device *dp) { - u8 buf[5]; + u8 buf[4]; int lane; int lane_count; @@ -295,10 +298,10 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) exynos_dp_set_training_pattern(dp, TRAINING_PTN1); /* Set RX training pattern */ - buf[0] = DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_1; exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]); + DPCD_ADDR_TRAINING_PATTERN_SET, + DPCD_SCRAMBLING_DISABLED | + DPCD_TRAINING_PATTERN_1); for (lane = 0; lane < lane_count; lane++) buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | @@ -308,7 +311,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) lane_count, buf); } -static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) +static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) { int shift = (lane & 1) * 4; u8 link_value = link_status[lane>>1]; @@ -316,7 +319,7 @@ static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) return (link_value >> shift) & 0xf; } -static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) +static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) { int lane; u8 lane_status; @@ -329,22 +332,23 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) return 0; } -static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count) +static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count) { int lane; u8 lane_align; u8 lane_status; - lane_align = link_status[2]; + lane_align = link_align[2]; if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0) return -EINVAL; for (lane = 0; lane < lane_count; lane++) { - lane_status = exynos_dp_get_lane_status(link_status, lane); + lane_status = exynos_dp_get_lane_status(link_align, lane); lane_status &= DPCD_CHANNEL_EQ_BITS; if (lane_status != DPCD_CHANNEL_EQ_BITS) return -EINVAL; } + return 0; } @@ -417,69 +421,17 @@ static unsigned int exynos_dp_get_lane_link_training( static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) { - if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) { - /* set to reduced bit rate */ - dp->link_train.link_rate = LINK_RATE_1_62GBPS; - dev_err(dp->dev, "set to bandwidth %.2x\n", - dp->link_train.link_rate); - dp->link_train.lt_state = START; - } else { - exynos_dp_training_pattern_dis(dp); - /* set enhanced mode if available */ - exynos_dp_set_enhanced_mode(dp); - dp->link_train.lt_state = FAILED; - } -} + exynos_dp_training_pattern_dis(dp); + exynos_dp_set_enhanced_mode(dp); -static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp, - u8 adjust_request[2]) -{ - int lane; - int lane_count; - u8 voltage_swing; - u8 pre_emphasis; - u8 training_lane; - - lane_count = dp->link_train.lane_count; - for (lane = 0; lane < lane_count; lane++) { - voltage_swing = exynos_dp_get_adjust_request_voltage( - adjust_request, lane); - pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( - adjust_request, lane); - training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | - DPCD_PRE_EMPHASIS_SET(pre_emphasis); - - if (voltage_swing == VOLTAGE_LEVEL_3 || - pre_emphasis == PRE_EMPHASIS_LEVEL_3) { - training_lane |= DPCD_MAX_SWING_REACHED; - training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; - } - dp->link_train.training_lane[lane] = training_lane; - } -} - -static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp, - u8 voltage_swing) -{ - int lane; - int lane_count; - - lane_count = dp->link_train.lane_count; - for (lane = 0; lane < lane_count; lane++) { - if (voltage_swing == VOLTAGE_LEVEL_3 || - dp->link_train.cr_loop[lane] == MAX_CR_LOOP) - return -EINVAL; - } - return 0; + dp->link_train.lt_state = FAILED; } static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) { - u8 data; - u8 link_status[6]; + u8 link_status[2]; int lane; int lane_count; - u8 buf[5]; u8 adjust_request[2]; u8 voltage_swing; @@ -488,100 +440,154 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) usleep_range(100, 101); - exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, - 6, link_status); lane_count = dp->link_train.lane_count; + exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, + 2, link_status); + if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ exynos_dp_set_training_pattern(dp, TRAINING_PTN2); - adjust_request[0] = link_status[4]; - adjust_request[1] = link_status[5]; + for (lane = 0; lane < lane_count; lane++) { + exynos_dp_read_bytes_from_dpcd(dp, + DPCD_ADDR_ADJUST_REQUEST_LANE0_1, + 2, adjust_request); + voltage_swing = exynos_dp_get_adjust_request_voltage( + adjust_request, lane); + pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( + adjust_request, lane); + training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | + DPCD_PRE_EMPHASIS_SET(pre_emphasis); - exynos_dp_get_adjust_train(dp, adjust_request); + if (voltage_swing == VOLTAGE_LEVEL_3) + training_lane |= DPCD_MAX_SWING_REACHED; + if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) + training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; - buf[0] = DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_2; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - buf[0]); + dp->link_train.training_lane[lane] = training_lane; - for (lane = 0; lane < lane_count; lane++) { exynos_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - buf[lane] = dp->link_train.training_lane[lane]; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET + lane, - buf[lane]); } - dp->link_train.lt_state = EQUALIZER_TRAINING; - } else { - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, - &data); - adjust_request[0] = data; - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE2_3, - &data); - adjust_request[1] = data; + exynos_dp_write_byte_to_dpcd(dp, + DPCD_ADDR_TRAINING_PATTERN_SET, + DPCD_SCRAMBLING_DISABLED | + DPCD_TRAINING_PATTERN_2); + + exynos_dp_write_bytes_to_dpcd(dp, + DPCD_ADDR_TRAINING_LANE0_SET, + lane_count, + dp->link_train.training_lane); + dev_info(dp->dev, "Link Training Clock Recovery success\n"); + dp->link_train.lt_state = EQUALIZER_TRAINING; + } else { for (lane = 0; lane < lane_count; lane++) { training_lane = exynos_dp_get_lane_link_training( dp, lane); + exynos_dp_read_bytes_from_dpcd(dp, + DPCD_ADDR_ADJUST_REQUEST_LANE0_1, + 2, adjust_request); voltage_swing = exynos_dp_get_adjust_request_voltage( adjust_request, lane); pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( adjust_request, lane); - if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) && - (DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)) - dp->link_train.cr_loop[lane]++; - dp->link_train.training_lane[lane] = training_lane; - } - if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) { - exynos_dp_reduce_link_rate(dp); - } else { - exynos_dp_get_adjust_train(dp, adjust_request); + if (voltage_swing == VOLTAGE_LEVEL_3 || + pre_emphasis == PRE_EMPHASIS_LEVEL_3) { + dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); + goto reduce_link_rate; + } - for (lane = 0; lane < lane_count; lane++) { - exynos_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], - lane); - buf[lane] = dp->link_train.training_lane[lane]; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET + lane, - buf[lane]); + if ((DPCD_VOLTAGE_SWING_GET(training_lane) == + voltage_swing) && + (DPCD_PRE_EMPHASIS_GET(training_lane) == + pre_emphasis)) { + dp->link_train.cr_loop[lane]++; + if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) { + dev_err(dp->dev, "CR Max loop\n"); + goto reduce_link_rate; + } } + + training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | + DPCD_PRE_EMPHASIS_SET(pre_emphasis); + + if (voltage_swing == VOLTAGE_LEVEL_3) + training_lane |= DPCD_MAX_SWING_REACHED; + if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) + training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; + + dp->link_train.training_lane[lane] = training_lane; + + exynos_dp_set_lane_link_training(dp, + dp->link_train.training_lane[lane], lane); } + + exynos_dp_write_bytes_to_dpcd(dp, + DPCD_ADDR_TRAINING_LANE0_SET, + lane_count, + dp->link_train.training_lane); } return 0; + +reduce_link_rate: + exynos_dp_reduce_link_rate(dp); + return -EIO; } static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) { - u8 link_status[6]; + u8 link_status[2]; + u8 link_align[3]; int lane; int lane_count; - u8 buf[5]; u32 reg; u8 adjust_request[2]; + u8 voltage_swing; + u8 pre_emphasis; + u8 training_lane; usleep_range(400, 401); - exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, - 6, link_status); lane_count = dp->link_train.lane_count; + exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, + 2, link_status); + if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { - adjust_request[0] = link_status[4]; - adjust_request[1] = link_status[5]; + link_align[0] = link_status[0]; + link_align[1] = link_status[1]; - if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { + exynos_dp_read_byte_from_dpcd(dp, + DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, + &link_align[2]); + + for (lane = 0; lane < lane_count; lane++) { + exynos_dp_read_bytes_from_dpcd(dp, + DPCD_ADDR_ADJUST_REQUEST_LANE0_1, + 2, adjust_request); + voltage_swing = exynos_dp_get_adjust_request_voltage( + adjust_request, lane); + pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( + adjust_request, lane); + training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | + DPCD_PRE_EMPHASIS_SET(pre_emphasis); + + if (voltage_swing == VOLTAGE_LEVEL_3) + training_lane |= DPCD_MAX_SWING_REACHED; + if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) + training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; + + dp->link_train.training_lane[lane] = training_lane; + } + + if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) { /* traing pattern Set to Normal */ exynos_dp_training_pattern_dis(dp); @@ -596,39 +602,42 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) dp->link_train.lane_count = reg; dev_dbg(dp->dev, "final lane count = %.2x\n", dp->link_train.lane_count); + /* set enhanced mode if available */ exynos_dp_set_enhanced_mode(dp); - dp->link_train.lt_state = FINISHED; } else { /* not all locked */ dp->link_train.eq_loop++; if (dp->link_train.eq_loop > MAX_EQ_LOOP) { - exynos_dp_reduce_link_rate(dp); - } else { - exynos_dp_get_adjust_train(dp, adjust_request); - - for (lane = 0; lane < lane_count; lane++) { - exynos_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], - lane); - buf[lane] = dp->link_train.training_lane[lane]; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET + lane, - buf[lane]); - } + dev_err(dp->dev, "EQ Max loop\n"); + goto reduce_link_rate; } + + for (lane = 0; lane < lane_count; lane++) + exynos_dp_set_lane_link_training(dp, + dp->link_train.training_lane[lane], + lane); + + exynos_dp_write_bytes_to_dpcd(dp, + DPCD_ADDR_TRAINING_LANE0_SET, + lane_count, + dp->link_train.training_lane); } } else { - exynos_dp_reduce_link_rate(dp); + goto reduce_link_rate; } return 0; + +reduce_link_rate: + exynos_dp_reduce_link_rate(dp); + return -EIO; } static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, - u8 *bandwidth) + u8 *bandwidth) { u8 data; @@ -641,7 +650,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, } static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, - u8 *lane_count) + u8 *lane_count) { u8 data; @@ -693,13 +702,7 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp, static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) { int retval = 0; - int training_finished; - - /* Turn off unnecessary lane */ - if (dp->link_train.lane_count == 1) - exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1); - - training_finished = 0; + int training_finished = 0; dp->link_train.lt_state = START; @@ -710,10 +713,14 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) exynos_dp_link_start(dp); break; case CLOCK_RECOVERY: - exynos_dp_process_clock_recovery(dp); + retval = exynos_dp_process_clock_recovery(dp); + if (retval) + dev_err(dp->dev, "LT CR failed!\n"); break; case EQUALIZER_TRAINING: - exynos_dp_process_equalizer_training(dp); + retval = exynos_dp_process_equalizer_training(dp); + if (retval) + dev_err(dp->dev, "LT EQ failed!\n"); break; case FINISHED: training_finished = 1; @@ -872,40 +879,33 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) dp->dev = &pdev->dev; - dp->clock = clk_get(&pdev->dev, "dp"); + dp->clock = devm_clk_get(&pdev->dev, "dp"); if (IS_ERR(dp->clock)) { dev_err(&pdev->dev, "failed to get clock\n"); return PTR_ERR(dp->clock); } - clk_enable(dp->clock); + clk_prepare_enable(dp->clock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get registers\n"); - ret = -EINVAL; - goto err_clock; - } dp->reg_base = devm_request_and_ioremap(&pdev->dev, res); if (!dp->reg_base) { dev_err(&pdev->dev, "failed to ioremap\n"); - ret = -ENOMEM; - goto err_clock; + return -ENOMEM; } dp->irq = platform_get_irq(pdev, 0); if (!dp->irq) { dev_err(&pdev->dev, "failed to get irq\n"); - ret = -ENODEV; - goto err_clock; + return -ENODEV; } ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, "exynos-dp", dp); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); - goto err_clock; + return ret; } dp->video_info = pdata->video_info; @@ -917,7 +917,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) ret = exynos_dp_detect_hpd(dp); if (ret) { dev_err(&pdev->dev, "unable to detect hpd\n"); - goto err_clock; + return ret; } exynos_dp_handle_edid(dp); @@ -926,7 +926,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) dp->video_info->link_rate); if (ret) { dev_err(&pdev->dev, "unable to do link train\n"); - goto err_clock; + return ret; } exynos_dp_enable_scramble(dp, 1); @@ -940,17 +940,12 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) ret = exynos_dp_config_video(dp, dp->video_info); if (ret) { dev_err(&pdev->dev, "unable to config video\n"); - goto err_clock; + return ret; } platform_set_drvdata(pdev, dp); return 0; - -err_clock: - clk_put(dp->clock); - - return ret; } static int __devexit exynos_dp_remove(struct platform_device *pdev) @@ -961,8 +956,7 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev) if (pdata && pdata->phy_exit) pdata->phy_exit(); - clk_disable(dp->clock); - clk_put(dp->clock); + clk_disable_unprepare(dp->clock); return 0; } @@ -977,7 +971,7 @@ static int exynos_dp_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(); - clk_disable(dp->clock); + clk_disable_unprepare(dp->clock); return 0; } @@ -991,7 +985,7 @@ static int exynos_dp_resume(struct device *dev) if (pdata && pdata->phy_init) pdata->phy_init(); - clk_enable(dp->clock); + clk_prepare_enable(dp->clock); exynos_dp_init_dp(dp); diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 8526e548c385..57b8a6531c0e 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h @@ -43,7 +43,7 @@ void exynos_dp_init_interrupt(struct exynos_dp_device *dp); void exynos_dp_reset(struct exynos_dp_device *dp); void exynos_dp_swreset(struct exynos_dp_device *dp); void exynos_dp_config_interrupt(struct exynos_dp_device *dp); -u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); +enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, enum analog_power_block block, @@ -105,7 +105,7 @@ u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp); u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp); u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); void exynos_dp_reset_macro(struct exynos_dp_device *dp); -int exynos_dp_init_video(struct exynos_dp_device *dp); +void exynos_dp_init_video(struct exynos_dp_device *dp); void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, u32 color_depth, @@ -144,7 +144,7 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); #define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 #define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 #define DPCD_ADDR_LANE0_1_STATUS 0x0202 -#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204 +#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 #define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 #define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 #define DPCD_ADDR_TEST_REQUEST 0x0218 diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c index 2db5b9aa250a..3f5ca8a0d5ea 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/video/exynos/exynos_dp_reg.c @@ -77,7 +77,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp) writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3); reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | - TX_CUR1_2X | TX_CUR_8_MA; + TX_CUR1_2X | TX_CUR_16_MA; writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1); reg = CH3_AMP_400_MV | CH2_AMP_400_MV | @@ -148,9 +148,6 @@ void exynos_dp_reset(struct exynos_dp_device *dp) writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH); writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); - - exynos_dp_init_analog_param(dp); - exynos_dp_init_interrupt(dp); } void exynos_dp_swreset(struct exynos_dp_device *dp) @@ -179,7 +176,7 @@ void exynos_dp_config_interrupt(struct exynos_dp_device *dp) writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK); } -u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) +enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) { u32 reg; @@ -401,6 +398,7 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) { int reg; int retval = 0; + int timeout_loop = 0; /* Enable AUX CH operation */ reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); @@ -409,8 +407,15 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) /* Is AUX CH command reply received? */ reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); - while (!(reg & RPLY_RECEIV)) + while (!(reg & RPLY_RECEIV)) { + timeout_loop++; + if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + dev_err(dp->dev, "AUX CH command reply failed!\n"); + return -ETIMEDOUT; + } reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); + usleep_range(10, 11); + } /* Clear interrupt source for AUX CH command reply */ writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA); @@ -471,7 +476,8 @@ int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } return retval; @@ -511,7 +517,8 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } /* Read data buffer */ @@ -575,7 +582,8 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } start_offset += cur_data_count; @@ -632,7 +640,8 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } for (cur_data_idx = 0; cur_data_idx < cur_data_count; @@ -677,7 +686,7 @@ int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, /* Start AUX transaction */ retval = exynos_dp_start_aux_transaction(dp); if (retval != 0) - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); return retval; } @@ -717,7 +726,8 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } /* Read data */ @@ -777,7 +787,9 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, + "%s: Aux Transaction fail!\n", + __func__); } /* Check if Rx sends defer */ reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM); @@ -883,7 +895,9 @@ void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); } @@ -891,7 +905,9 @@ void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); } @@ -899,7 +915,9 @@ void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); } @@ -907,7 +925,9 @@ void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); } @@ -994,7 +1014,7 @@ void exynos_dp_reset_macro(struct exynos_dp_device *dp) writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); } -int exynos_dp_init_video(struct exynos_dp_device *dp) +void exynos_dp_init_video(struct exynos_dp_device *dp) { u32 reg; @@ -1012,8 +1032,6 @@ int exynos_dp_init_video(struct exynos_dp_device *dp) reg = VID_HRES_TH(2) | VID_VRES_TH(0); writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); - - return 0; } void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h index 125b27cd57ae..1f2f014cfe88 100644 --- a/drivers/video/exynos/exynos_dp_reg.h +++ b/drivers/video/exynos/exynos_dp_reg.h @@ -187,7 +187,7 @@ #define PD_RING_OSC (0x1 << 6) #define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) #define TX_CUR1_2X (0x1 << 2) -#define TX_CUR_8_MA (0x2 << 0) +#define TX_CUR_16_MA (0x3 << 0) /* EXYNOS_DP_TX_AMP_TUNING_CTL */ #define CH3_AMP_400_MV (0x0 << 24) @@ -285,6 +285,7 @@ #define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) /* EXYNOS_DP_LN0_LINK_TRAINING_CTL */ +#define PRE_EMPHASIS_SET_MASK (0x3 << 3) #define PRE_EMPHASIS_SET_SHIFT (3) /* EXYNOS_DP_DEBUG_CTL */ diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 663c308d0e73..07d70a3a628b 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -205,7 +205,8 @@ int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) return 0; } -struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) +static struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device( + struct mipi_dsim_lcd_driver *lcd_drv) { struct mipi_dsim_ddi *dsim_ddi, *next; struct mipi_dsim_lcd_device *lcd_dev; @@ -265,7 +266,8 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) } -struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, +static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi( + struct mipi_dsim_device *dsim, const char *name) { struct mipi_dsim_ddi *dsim_ddi, *next; @@ -373,6 +375,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) dsim->clock = clk_get(&pdev->dev, "dsim0"); if (IS_ERR(dsim->clock)) { dev_err(&pdev->dev, "failed to get dsim clock source\n"); + ret = -ENODEV; goto err_clock_get; } @@ -381,6 +384,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get io memory region\n"); + ret = -ENODEV; goto err_platform_get; } @@ -405,6 +409,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); if (!dsim_ddi) { dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); + ret = -EINVAL; goto err_bind; } diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index 47b533a183be..3cd29a4fc10a 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -79,11 +79,6 @@ irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id) struct mipi_dsim_device *dsim = dev_id; unsigned int intsrc, intmsk; - if (dsim == NULL) { - dev_err(dsim->dev, "%s: wrong parameter\n", __func__); - return IRQ_NONE; - } - intsrc = exynos_mipi_dsi_read_interrupt(dsim); intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim); intmsk = ~intmsk & intsrc; @@ -288,9 +283,6 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, mutex_unlock(&dsim->lock); return -EINVAL; } - - mutex_unlock(&dsim->lock); - return 0; } static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim, diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 458c00664ade..ede9e55413f8 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1501,8 +1501,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) unsigned int i; int ret; - data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), - &dma_addr, GFP_DMA | __GFP_ZERO); + data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), + &dma_addr, GFP_DMA | __GFP_ZERO); if (!data) return -ENOMEM; data->dma_addr = dma_addr; @@ -1628,9 +1628,6 @@ error: iounmap(data->diu_reg); - dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, - data->dma_addr); - return ret; } @@ -1648,9 +1645,6 @@ static int fsl_diu_remove(struct platform_device *pdev) iounmap(data->diu_reg); - dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, - data->dma_addr); - return 0; } diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 05e2a8a99d8f..3dad31975db8 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/io.h> #ifdef CONFIG_X86 #include <asm/mtrr.h> @@ -28,7 +29,6 @@ #include <asm/addrspace.h> #endif #include <asm/byteorder.h> -#include <asm/io.h> #include <asm/tlbflush.h> #include <video/gbe.h> @@ -1156,7 +1156,8 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) goto out_release_framebuffer; } - gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe)); + gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE, + sizeof(struct sgi_gbe)); if (!gbe) { printk(KERN_ERR "gbefb: couldn't map mmio region\n"); ret = -ENXIO; @@ -1170,12 +1171,13 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) if (!gbe_tiles.cpu) { printk(KERN_ERR "gbefb: couldn't allocate tiles table\n"); ret = -ENOMEM; - goto out_unmap; + goto out_release_mem_region; } if (gbe_mem_phys) { /* memory was allocated at boot time */ - gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size); + gbe_mem = devm_ioremap_nocache(&p_dev->dev, gbe_mem_phys, + gbe_mem_size); if (!gbe_mem) { printk(KERN_ERR "gbefb: couldn't map framebuffer\n"); ret = -ENOMEM; @@ -1241,13 +1243,9 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) out_gbe_unmap: if (gbe_dma_addr) dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); - else - iounmap(gbe_mem); out_tiles_free: dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), (void *)gbe_tiles.cpu, gbe_tiles.dma); -out_unmap: - iounmap(gbe); out_release_mem_region: release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); out_release_framebuffer: @@ -1264,12 +1262,9 @@ static int __devexit gbefb_remove(struct platform_device* p_dev) gbe_turn_off(); if (gbe_dma_addr) dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); - else - iounmap(gbe_mem); dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), (void *)gbe_tiles.cpu, gbe_tiles.dma); release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); - iounmap(gbe); gbefb_remove_sysfs(&p_dev->dev); framebuffer_release(info); diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index ebf8495ff198..7324865f965f 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -210,6 +210,7 @@ static int __devinit hpfb_init_one(unsigned long phys_base, unsigned long virt_base) { unsigned long fboff, fb_width, fb_height, fb_start; + int ret; fb_regs = virt_base; fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB); @@ -290,19 +291,29 @@ static int __devinit hpfb_init_one(unsigned long phys_base, fb_info.var = hpfb_defined; fb_info.screen_base = (char *)fb_start; - fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0); + ret = fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0); + if (ret < 0) + goto unmap_screen_base; - if (register_framebuffer(&fb_info) < 0) { - fb_dealloc_cmap(&fb_info.cmap); - iounmap(fb_info.screen_base); - fb_info.screen_base = NULL; - return 1; - } + ret = register_framebuffer(&fb_info); + if (ret < 0) + goto dealloc_cmap; printk(KERN_INFO "fb%d: %s frame buffer device\n", fb_info.node, fb_info.fix.id); return 0; + +dealloc_cmap: + fb_dealloc_cmap(&fb_info.cmap); + +unmap_screen_base: + if (fb_info.screen_base) { + iounmap(fb_info.screen_base); + fb_info.screen_base = NULL; + } + + return ret; } /* @@ -345,6 +356,9 @@ static void __devexit hpfb_remove_one(struct dio_dev *d) if (d->scode >= DIOII_SCBASE) iounmap((void *)fb_regs); release_mem_region(d->resource.start, resource_size(&d->resource)); + fb_dealloc_cmap(&fb_info.cmap); + if (fb_info.screen_base) + iounmap(fb_info.screen_base); } static struct dio_device_id hpfb_dio_tbl[] = { diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 53ffdfc82a75..cf2688de0832 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -803,6 +803,7 @@ static int __init imxfb_probe(struct platform_device *pdev) fbi->regs = ioremap(res->start, resource_size(res)); if (fbi->regs == NULL) { dev_err(&pdev->dev, "Cannot map frame buffer registers\n"); + ret = -ENOMEM; goto failed_ioremap; } diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c index 3c63fc24bb1f..4d25711b9982 100644 --- a/drivers/video/jz4740_fb.c +++ b/drivers/video/jz4740_fb.c @@ -632,23 +632,10 @@ static int __devinit jzfb_probe(struct platform_device *pdev) return -ENXIO; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "Failed to get register memory resource\n"); - return -ENXIO; - } - - mem = request_mem_region(mem->start, resource_size(mem), pdev->name); - if (!mem) { - dev_err(&pdev->dev, "Failed to request register memory region\n"); - return -EBUSY; - } - fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); if (!fb) { dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); - ret = -ENOMEM; - goto err_release_mem_region; + return -ENOMEM; } fb->fbops = &jzfb_ops; @@ -657,27 +644,26 @@ static int __devinit jzfb_probe(struct platform_device *pdev) jzfb = fb->par; jzfb->pdev = pdev; jzfb->pdata = pdata; - jzfb->mem = mem; - jzfb->ldclk = clk_get(&pdev->dev, "lcd"); + jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd"); if (IS_ERR(jzfb->ldclk)) { ret = PTR_ERR(jzfb->ldclk); dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); goto err_framebuffer_release; } - jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk"); + jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk"); if (IS_ERR(jzfb->lpclk)) { ret = PTR_ERR(jzfb->lpclk); dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); - goto err_put_ldclk; + goto err_framebuffer_release; } - jzfb->base = ioremap(mem->start, resource_size(mem)); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + jzfb->base = devm_request_and_ioremap(&pdev->dev, mem); if (!jzfb->base) { - dev_err(&pdev->dev, "Failed to ioremap register memory region\n"); ret = -EBUSY; - goto err_put_lpclk; + goto err_framebuffer_release; } platform_set_drvdata(pdev, jzfb); @@ -693,7 +679,7 @@ static int __devinit jzfb_probe(struct platform_device *pdev) ret = jzfb_alloc_devmem(jzfb); if (ret) { dev_err(&pdev->dev, "Failed to allocate video memory\n"); - goto err_iounmap; + goto err_framebuffer_release; } fb->fix = jzfb_fix; @@ -734,16 +720,8 @@ err_free_devmem: fb_dealloc_cmap(&fb->cmap); jzfb_free_devmem(jzfb); -err_iounmap: - iounmap(jzfb->base); -err_put_lpclk: - clk_put(jzfb->lpclk); -err_put_ldclk: - clk_put(jzfb->ldclk); err_framebuffer_release: framebuffer_release(fb); -err_release_mem_region: - release_mem_region(mem->start, resource_size(mem)); return ret; } @@ -756,17 +734,11 @@ static int __devexit jzfb_remove(struct platform_device *pdev) jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); - iounmap(jzfb->base); - release_mem_region(jzfb->mem->start, resource_size(jzfb->mem)); - fb_dealloc_cmap(&jzfb->fb->cmap); jzfb_free_devmem(jzfb); platform_set_drvdata(pdev, NULL); - clk_put(jzfb->lpclk); - clk_put(jzfb->ldclk); - framebuffer_release(jzfb->fb); return 0; diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index 57d940be5f3d..d68e332aa21c 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -1052,12 +1052,14 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev, break; default: /* should never occur */ + ret = -EIO; goto rel_reg; } par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram); if (par->fb_base == NULL) { dev_err(dev, "Cannot map framebuffer\n"); + ret = -EIO; goto rel_reg; } @@ -1073,11 +1075,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev, dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n", (unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len); - if (mb862xx_pci_gdc_init(par)) + ret = mb862xx_pci_gdc_init(par); + if (ret) goto io_unmap; - if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED, - DRV_NAME, (void *)par)) { + ret = request_irq(par->irq, mb862xx_intr, IRQF_SHARED, + DRV_NAME, (void *)par); + if (ret) { dev_err(dev, "Cannot request irq\n"); goto io_unmap; } diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 85e4f44bfa61..6563e50413c1 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -26,8 +26,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/uaccess.h> - -#include <asm/io.h> +#include <linux/io.h> #include <video/mbxfb.h> @@ -939,8 +938,9 @@ static int __devinit mbxfb_probe(struct platform_device *dev) } mfbi->reg_phys_addr = mfbi->reg_res->start; - mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr, - res_size(mfbi->reg_req)); + mfbi->reg_virt_addr = devm_ioremap_nocache(&dev->dev, + mfbi->reg_phys_addr, + res_size(mfbi->reg_req)); if (!mfbi->reg_virt_addr) { dev_err(&dev->dev, "failed to ioremap Marathon registers\n"); ret = -EINVAL; @@ -948,12 +948,12 @@ static int __devinit mbxfb_probe(struct platform_device *dev) } virt_base_2700 = mfbi->reg_virt_addr; - mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, - res_size(mfbi->fb_req)); + mfbi->fb_virt_addr = devm_ioremap_nocache(&dev->dev, mfbi->fb_phys_addr, + res_size(mfbi->fb_req)); if (!mfbi->fb_virt_addr) { dev_err(&dev->dev, "failed to ioremap frame buffer\n"); ret = -EINVAL; - goto err4; + goto err3; } fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); @@ -971,7 +971,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev) if (ret < 0) { dev_err(&dev->dev, "fb_alloc_cmap failed\n"); ret = -EINVAL; - goto err5; + goto err3; } platform_set_drvdata(dev, fbi); @@ -996,10 +996,6 @@ static int __devinit mbxfb_probe(struct platform_device *dev) err6: fb_dealloc_cmap(&fbi->cmap); -err5: - iounmap(mfbi->fb_virt_addr); -err4: - iounmap(mfbi->reg_virt_addr); err3: release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res)); err2: @@ -1026,10 +1022,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev) if (mfbi->platform_remove) mfbi->platform_remove(fbi); - if (mfbi->fb_virt_addr) - iounmap(mfbi->fb_virt_addr); - if (mfbi->reg_virt_addr) - iounmap(mfbi->reg_virt_addr); + if (mfbi->reg_req) release_mem_region(mfbi->reg_req->start, res_size(mfbi->reg_req)); diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c index bf73f0480061..35ac9e8bee63 100644 --- a/drivers/video/msm/mddi.c +++ b/drivers/video/msm/mddi.c @@ -26,9 +26,6 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/sched.h> -#include <mach/msm_iomap.h> -#include <mach/irqs.h> -#include <mach/board.h> #include <linux/platform_data/video-msm_fb.h> #include "mddi_hw.h" diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c index d7a5bf84fb2a..f96df32e5509 100644 --- a/drivers/video/msm/mddi_client_nt35399.c +++ b/drivers/video/msm/mddi_client_nt35399.c @@ -189,8 +189,9 @@ static int mddi_nt35399_probe(struct platform_device *pdev) int ret; - struct panel_info *panel = kzalloc(sizeof(struct panel_info), - GFP_KERNEL); + struct panel_info *panel = devm_kzalloc(&pdev->dev, + sizeof(struct panel_info), + GFP_KERNEL); printk(KERN_DEBUG "%s: enter.\n", __func__); @@ -233,7 +234,6 @@ static int mddi_nt35399_remove(struct platform_device *pdev) struct panel_info *panel = platform_get_drvdata(pdev); setup_vsync(panel, 0); - kfree(panel); return 0; } diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 2e0f3bab6114..f2566c19e71c 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -25,7 +25,6 @@ #include <linux/major.h> #include <linux/slab.h> -#include <mach/msm_iomap.h> #include <linux/platform_data/video-msm_fb.h> #include <linux/platform_device.h> #include <linux/export.h> diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h index a0bacf581b32..35848d741001 100644 --- a/drivers/video/msm/mdp_hw.h +++ b/drivers/video/msm/mdp_hw.h @@ -15,7 +15,6 @@ #ifndef _MDP_HW_H_ #define _MDP_HW_H_ -#include <mach/msm_iomap.h> #include <linux/platform_data/video-msm_fb.h> struct mdp_info { diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index d7381088a180..ce1d452464ed 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -1568,7 +1568,8 @@ static int mx3fb_remove(struct platform_device *dev) static struct platform_driver mx3fb_driver = { .driver = { - .name = MX3FB_NAME, + .name = MX3FB_NAME, + .owner = THIS_MODULE, }, .probe = mx3fb_probe, .remove = mx3fb_remove, diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 93387555337e..475dfee82c4a 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -387,7 +387,7 @@ static int nuc900fb_init_registers(struct fb_info *info) * The buffer should be a non-cached, non-buffered, memory region * to allow palette and pixel writes without flushing the cache. */ -static int __init nuc900fb_map_video_memory(struct fb_info *info) +static int __devinit nuc900fb_map_video_memory(struct fb_info *info) { struct nuc900fb_info *fbi = info->par; dma_addr_t map_dma; diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 9f1d23c319cb..f349ee6f0cea 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -27,7 +27,6 @@ #include <linux/clk.h> #include <linux/interrupt.h> -#include <plat/dma.h> #include "omapfb.h" #define HWA742_REV_CODE_REG 0x0 diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c index 88c31eb0cd6c..ff4fb624b904 100644 --- a/drivers/video/omap/lcd_palmte.c +++ b/drivers/video/omap/lcd_palmte.c @@ -23,7 +23,6 @@ #include <linux/platform_device.h> #include <linux/io.h> -#include <plat/fpga.h> #include "omapfb.h" static int palmte_panel_init(struct lcd_panel *panel, diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index f54b463709e9..4351c438b76f 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -131,15 +131,6 @@ static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) * LCD controller and LCD DMA * --------------------------------------------------------------------------- */ -/* Lookup table to map elem size to elem type. */ -static const int dma_elem_type[] = { - 0, - OMAP_DMA_DATA_TYPE_S8, - OMAP_DMA_DATA_TYPE_S16, - 0, - OMAP_DMA_DATA_TYPE_S32, -}; - /* * Allocate resources needed for LCD controller and LCD DMA operations. Video * memory is allocated from system memory according to the virtual display diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index eaeed4340e04..c835aa70f96f 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -600,6 +600,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) mutex_lock(&md->mutex); + omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs); + r = omapdss_sdi_display_enable(dssdev); if (r) { pr_err("%s sdi enable failed\n", __func__); @@ -731,18 +734,9 @@ static int acx_panel_resume(struct omap_dss_device *dssdev) static void acx_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - omapdss_sdi_display_disable(dssdev); + omapdss_sdi_set_timings(dssdev, timings); dssdev->panel.timings = *timings; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = omapdss_sdi_display_enable(dssdev); - if (r) - dev_err(&dssdev->dev, "%s enable failed\n", __func__); - } } static int acx_panel_check_timings(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index bc5af2500eb9..88295c526815 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -545,6 +545,8 @@ struct panel_drv_data { struct omap_dss_device *dssdev; struct panel_config *panel_config; + + struct mutex lock; }; static inline struct panel_generic_dpi_data @@ -563,6 +565,9 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -634,6 +639,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) drv_data->dssdev = dssdev; drv_data->panel_config = panel_config; + mutex_init(&drv_data->lock); + dev_set_drvdata(&dssdev->dev, drv_data); return 0; @@ -652,56 +659,108 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) { - int r = 0; + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); r = generic_dpi_panel_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; +err: + mutex_unlock(&drv_data->lock); - return 0; + return r; } static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) { + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + generic_dpi_panel_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&drv_data->lock); } static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) { + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + generic_dpi_panel_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + mutex_unlock(&drv_data->lock); + return 0; } static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) { - int r = 0; + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); r = generic_dpi_panel_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - return 0; +err: + mutex_unlock(&drv_data->lock); + + return r; } static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dpi_set_timings(dssdev, timings); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + + omapdss_dpi_set_timings(dssdev, timings); + + dssdev->panel.timings = *timings; + + mutex_unlock(&drv_data->lock); +} + +static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + + *timings = dssdev->panel.timings; + + mutex_unlock(&drv_data->lock); } static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - return dpi_check_timings(dssdev, timings); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); + + r = dpi_check_timings(dssdev, timings); + + mutex_unlock(&drv_data->lock); + + return r; } static struct omap_dss_driver dpi_driver = { @@ -714,6 +773,7 @@ static struct omap_dss_driver dpi_driver = { .resume = generic_dpi_panel_resume, .set_timings = generic_dpi_panel_set_timings, + .get_timings = generic_dpi_panel_get_timings, .check_timings = generic_dpi_panel_check_timings, .driver = { diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 802807798846..90c1cabf244e 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -55,6 +55,9 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index e6c115373c00..3fc5ad081a21 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -150,11 +150,17 @@ static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev, BLIZZARD_SRC_WRITE_LCD : BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; - omap_rfbi_configure(dssdev, 16, 8); + omapdss_rfbi_set_pixel_size(dssdev, 16); + omapdss_rfbi_set_data_lines(dssdev, 8); + + omap_rfbi_configure(dssdev); blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18); - omap_rfbi_configure(dssdev, 16, 16); + omapdss_rfbi_set_pixel_size(dssdev, 16); + omapdss_rfbi_set_data_lines(dssdev, 16); + + omap_rfbi_configure(dssdev); } static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf, @@ -297,6 +303,12 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) goto err_plat_en; } + omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); + omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines); + omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings); + r = omapdss_rfbi_display_enable(dssdev); if (r) goto err_rfbi_en; @@ -477,6 +489,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) dssdev->panel.timings.y_res = 480; dssdev->ctrl.pixel_size = 16; dssdev->ctrl.rfbi_timings = n8x0_panel_timings; + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; memset(&props, 0, sizeof(props)); props.max_brightness = 127; @@ -625,17 +638,25 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct panel_drv_data *ddata = get_drv_data(dssdev); + u16 dw, dh; dev_dbg(&dssdev->dev, "update\n"); + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + + if (x != 0 || y != 0 || w != dw || h != dh) { + dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n", + x, y, w, h); + return -EINVAL; + } + mutex_lock(&ddata->lock); rfbi_bus_lock(); - omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h); - blizzard_ctrl_setup_update(dssdev, x, y, w, h); - omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL); + omap_rfbi_update(dssdev, update_done, NULL); mutex_unlock(&ddata->lock); diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index b122b0f31c43..908fd268f3dc 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -175,6 +175,9 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 2d35bd388860..9df87640ddd2 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -377,6 +377,10 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) * then only i2c commands can be successfully sent to dpp2600 */ msleep(1000); + + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DPI\n"); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index bd86ba9ccf76..1ec3b277ff15 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -142,6 +142,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 6b5e6e0e202f..f2f644680ca8 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -121,6 +121,18 @@ struct taal_data { struct omap_dss_device *dssdev; + /* panel specific HW info */ + struct panel_config *panel_config; + + /* panel HW configuration from DT or platform data */ + int reset_gpio; + int ext_te_gpio; + + bool use_dsi_backlight; + + struct omap_dsi_pin_config pin_config; + + /* runtime variables */ bool enabled; u8 rotate; bool mirror; @@ -145,16 +157,8 @@ struct taal_data { bool ulps_enabled; unsigned ulps_timeout; struct delayed_work ulps_work; - - struct panel_config *panel_config; }; -static inline struct nokia_dsi_panel_data -*get_panel_data(const struct omap_dss_device *dssdev) -{ - return (struct nokia_dsi_panel_data *) dssdev->data; -} - static void taal_esd_work(struct work_struct *work); static void taal_ulps_work(struct work_struct *work); @@ -371,7 +375,6 @@ static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) static int taal_enter_ulps(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (td->ulps_enabled) @@ -383,7 +386,8 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev) if (r) goto err; - disable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + disable_irq(gpio_to_irq(td->ext_te_gpio)); omapdss_dsi_display_disable(dssdev, false, true); @@ -405,7 +409,6 @@ err: static int taal_exit_ulps(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (!td->ulps_enabled) @@ -425,7 +428,8 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) goto err2; } - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + enable_irq(gpio_to_irq(td->ext_te_gpio)); taal_queue_ulps_work(dssdev); @@ -438,7 +442,8 @@ err2: r = taal_panel_reset(dssdev); if (!r) { - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + enable_irq(gpio_to_irq(td->ext_te_gpio)); td->ulps_enabled = false; } err1: @@ -835,94 +840,135 @@ static struct attribute_group taal_attr_group = { static void taal_hw_reset(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - if (panel_data->reset_gpio == -1) + if (!gpio_is_valid(td->reset_gpio)) return; - gpio_set_value(panel_data->reset_gpio, 1); + gpio_set_value(td->reset_gpio, 1); if (td->panel_config->reset_sequence.high) udelay(td->panel_config->reset_sequence.high); /* reset the panel */ - gpio_set_value(panel_data->reset_gpio, 0); + gpio_set_value(td->reset_gpio, 0); /* assert reset */ if (td->panel_config->reset_sequence.low) udelay(td->panel_config->reset_sequence.low); - gpio_set_value(panel_data->reset_gpio, 1); + gpio_set_value(td->reset_gpio, 1); /* wait after releasing reset */ if (td->panel_config->sleep.hw_reset) msleep(td->panel_config->sleep.hw_reset); } +static void taal_probe_pdata(struct taal_data *td, + const struct nokia_dsi_panel_data *pdata) +{ + td->reset_gpio = pdata->reset_gpio; + + if (pdata->use_ext_te) + td->ext_te_gpio = pdata->ext_te_gpio; + else + td->ext_te_gpio = -1; + + td->esd_interval = pdata->esd_interval; + td->ulps_timeout = pdata->ulps_timeout; + + td->use_dsi_backlight = pdata->use_dsi_backlight; + + td->pin_config = pdata->pin_config; +} + static int taal_probe(struct omap_dss_device *dssdev) { struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev = NULL; - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - struct panel_config *panel_config = NULL; int r, i; + const char *panel_name; dev_dbg(&dssdev->dev, "probe\n"); - if (!panel_data || !panel_data->name) { - r = -EINVAL; - goto err; + td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL); + if (!td) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, td); + td->dssdev = dssdev; + + if (dssdev->data) { + const struct nokia_dsi_panel_data *pdata = dssdev->data; + + taal_probe_pdata(td, pdata); + + panel_name = pdata->name; + } else { + return -ENODEV; } + if (panel_name == NULL) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { - if (strcmp(panel_data->name, panel_configs[i].name) == 0) { - panel_config = &panel_configs[i]; + if (strcmp(panel_name, panel_configs[i].name) == 0) { + td->panel_config = &panel_configs[i]; break; } } - if (!panel_config) { - r = -EINVAL; - goto err; - } + if (!td->panel_config) + return -EINVAL; - dssdev->panel.timings = panel_config->timings; + dssdev->panel.timings = td->panel_config->timings; dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; - - td = kzalloc(sizeof(*td), GFP_KERNEL); - if (!td) { - r = -ENOMEM; - goto err; - } - td->dssdev = dssdev; - td->panel_config = panel_config; - td->esd_interval = panel_data->esd_interval; - td->ulps_enabled = false; - td->ulps_timeout = panel_data->ulps_timeout; + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | + OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; mutex_init(&td->lock); atomic_set(&td->do_update, 0); - td->workqueue = create_singlethread_workqueue("taal_esd"); - if (td->workqueue == NULL) { - dev_err(&dssdev->dev, "can't create ESD workqueue\n"); - r = -ENOMEM; - goto err_wq; + if (gpio_is_valid(td->reset_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio, + GPIOF_OUT_INIT_LOW, "taal rst"); + if (r) { + dev_err(&dssdev->dev, "failed to request reset gpio\n"); + return r; + } } - INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); - INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); - dev_set_drvdata(&dssdev->dev, td); + if (gpio_is_valid(td->ext_te_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio, + GPIOF_IN, "taal irq"); + if (r) { + dev_err(&dssdev->dev, "GPIO request failed\n"); + return r; + } + + r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio), + taal_te_isr, + IRQF_TRIGGER_RISING, + "taal vsync", dssdev); - if (gpio_is_valid(panel_data->reset_gpio)) { - r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW, - "taal rst"); if (r) { - dev_err(&dssdev->dev, "failed to request reset gpio\n"); - goto err_rst_gpio; + dev_err(&dssdev->dev, "IRQ request failed\n"); + return r; } + + INIT_DEFERRABLE_WORK(&td->te_timeout_work, + taal_te_timeout_work_callback); + + dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } + td->workqueue = create_singlethread_workqueue("taal_esd"); + if (td->workqueue == NULL) { + dev_err(&dssdev->dev, "can't create ESD workqueue\n"); + return -ENOMEM; + } + INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); + INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); + taal_hw_reset(dssdev); - if (panel_data->use_dsi_backlight) { + if (td->use_dsi_backlight) { memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 255; @@ -943,31 +989,6 @@ static int taal_probe(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); } - if (panel_data->use_ext_te) { - int gpio = panel_data->ext_te_gpio; - - r = gpio_request_one(gpio, GPIOF_IN, "taal irq"); - if (r) { - dev_err(&dssdev->dev, "GPIO request failed\n"); - goto err_gpio; - } - - r = request_irq(gpio_to_irq(gpio), taal_te_isr, - IRQF_TRIGGER_RISING, - "taal vsync", dssdev); - - if (r) { - dev_err(&dssdev->dev, "IRQ request failed\n"); - gpio_free(gpio); - goto err_irq; - } - - INIT_DEFERRABLE_WORK(&td->te_timeout_work, - taal_te_timeout_work_callback); - - dev_dbg(&dssdev->dev, "Using GPIO TE\n"); - } - r = omap_dsi_request_vc(dssdev, &td->channel); if (r) { dev_err(&dssdev->dev, "failed to get virtual channel\n"); @@ -991,29 +1012,16 @@ static int taal_probe(struct omap_dss_device *dssdev) err_vc_id: omap_dsi_release_vc(dssdev, td->channel); err_req_vc: - if (panel_data->use_ext_te) - free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); -err_irq: - if (panel_data->use_ext_te) - gpio_free(panel_data->ext_te_gpio); -err_gpio: if (bldev != NULL) backlight_device_unregister(bldev); err_bl: - if (gpio_is_valid(panel_data->reset_gpio)) - gpio_free(panel_data->reset_gpio); -err_rst_gpio: destroy_workqueue(td->workqueue); -err_wq: - kfree(td); -err: return r; } static void __exit taal_remove(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); struct backlight_device *bldev; dev_dbg(&dssdev->dev, "remove\n"); @@ -1021,12 +1029,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); omap_dsi_release_vc(dssdev, td->channel); - if (panel_data->use_ext_te) { - int gpio = panel_data->ext_te_gpio; - free_irq(gpio_to_irq(gpio), dssdev); - gpio_free(gpio); - } - bldev = td->bldev; if (bldev != NULL) { bldev->props.power = FB_BLANK_POWERDOWN; @@ -1040,26 +1042,31 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) /* reset, to be sure that the panel is in a valid state */ taal_hw_reset(dssdev); - - if (gpio_is_valid(panel_data->reset_gpio)) - gpio_free(panel_data->reset_gpio); - - kfree(td); } static int taal_power_on(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 id1, id2, id3; int r; - r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config); + r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); if (r) { dev_err(&dssdev->dev, "failed to configure DSI pins\n"); goto err0; }; + omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888); + omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE); + + r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000); + if (r) { + dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); + goto err0; + } + r = omapdss_dsi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DSI\n"); @@ -1356,7 +1363,6 @@ static int taal_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); @@ -1380,7 +1386,7 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - if (td->te_enabled && panel_data->use_ext_te) { + if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { schedule_delayed_work(&td->te_timeout_work, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); @@ -1419,7 +1425,6 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (enable) @@ -1427,7 +1432,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) else r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF); - if (!panel_data->use_ext_te) + if (!gpio_is_valid(td->ext_te_gpio)) omapdss_dsi_enable_te(dssdev, enable); if (td->panel_config->sleep.enable_te) @@ -1487,6 +1492,7 @@ static int taal_get_te(struct omap_dss_device *dssdev) static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + u16 dw, dh; int r; dev_dbg(&dssdev->dev, "rotate %d\n", rotate); @@ -1508,6 +1514,16 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) goto err; } + if (rotate == 0 || rotate == 2) { + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + } else { + dw = dssdev->panel.timings.y_res; + dh = dssdev->panel.timings.x_res; + } + + omapdss_dsi_set_size(dssdev, dw, dh); + td->rotate = rotate; dsi_bus_unlock(dssdev); @@ -1726,7 +1742,6 @@ static void taal_esd_work(struct work_struct *work) struct taal_data *td = container_of(work, struct taal_data, esd_work.work); struct omap_dss_device *dssdev = td->dssdev; - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 state1, state2; int r; @@ -1773,7 +1788,7 @@ static void taal_esd_work(struct work_struct *work) } /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ - if (td->te_enabled && panel_data->use_ext_te) { + if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); if (r) goto err; diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 40cc0cfa5d17..383811cf8648 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -65,6 +65,9 @@ static int tfp410_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -116,8 +119,8 @@ static int tfp410_probe(struct omap_dss_device *dssdev) } if (gpio_is_valid(ddata->pd_gpio)) { - r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW, - "tfp410 pd"); + r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio, + GPIOF_OUT_INIT_LOW, "tfp410 pd"); if (r) { dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", ddata->pd_gpio); @@ -132,8 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev) if (!adapter) { dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", i2c_bus_num); - r = -EINVAL; - goto err_i2c; + return -EINVAL; } ddata->i2c_adapter = adapter; @@ -142,10 +144,6 @@ static int tfp410_probe(struct omap_dss_device *dssdev) dev_set_drvdata(&dssdev->dev, ddata); return 0; -err_i2c: - if (gpio_is_valid(ddata->pd_gpio)) - gpio_free(ddata->pd_gpio); - return r; } static void __exit tfp410_remove(struct omap_dss_device *dssdev) @@ -157,9 +155,6 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev) if (ddata->i2c_adapter) i2c_put_adapter(ddata->i2c_adapter); - if (gpio_is_valid(ddata->pd_gpio)) - gpio_free(ddata->pd_gpio); - dev_set_drvdata(&dssdev->dev, NULL); mutex_unlock(&ddata->lock); @@ -231,7 +226,8 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev, struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); mutex_lock(&ddata->lock); - dpi_set_timings(dssdev, timings); + omapdss_dpi_set_timings(dssdev, timings); + dssdev->panel.timings = *timings; mutex_unlock(&ddata->lock); } diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index fa7baa650ae0..b5e6dbc59f0a 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -337,6 +337,9 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -480,7 +483,9 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev) static void tpo_td043_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dpi_set_timings(dssdev, timings); + omapdss_dpi_set_timings(dssdev, timings); + + dssdev->panel.timings = *timings; } static int tpo_td043_check_timings(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index b337a8469fd8..80f5390aa136 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -84,7 +84,7 @@ config OMAP2_DSS_SDI config OMAP2_DSS_DSI bool "DSI support" - depends on ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5 default n help MIPI DSI (Display Serial Interface) support. diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 5c450b0f94d0..4549869bfe1a 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,9 +1,9 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - manager.o overlay.o apply.o + manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o -omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o +omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 0fefc68372b9..19d66f471b4b 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -111,9 +111,6 @@ static struct { struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; - bool fifo_merge_dirty; - bool fifo_merge; - bool irq_enabled; } dss_data; @@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void) int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); - struct mgr_priv_data *mp; + struct mgr_priv_data *mp = get_mgr_priv(mgr); u32 irq; + unsigned long flags; int r; int i; - struct omap_dss_device *dssdev = mgr->device; - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + spin_lock_irqsave(&data_lock, flags); + + if (mgr_manual_update(mgr)) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } - if (mgr_manual_update(mgr)) + if (!mp->enabled) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } + + spin_unlock_irqrestore(&data_lock, flags); r = dispc_runtime_get(); if (r) @@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) irq = dispc_mgr_get_vsync_irq(mgr->id); - mp = get_mgr_priv(mgr); i = 0; while (1) { - unsigned long flags; bool shadow_dirty, dirty; spin_lock_irqsave(&data_lock, flags); @@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); struct ovl_priv_data *op; - struct omap_dss_device *dssdev; + struct mgr_priv_data *mp; u32 irq; + unsigned long flags; int r; int i; if (!ovl->manager) return 0; - dssdev = ovl->manager->device; + mp = get_mgr_priv(ovl->manager); + + spin_lock_irqsave(&data_lock, flags); - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + if (ovl_manual_update(ovl)) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } - if (ovl_manual_update(ovl)) + if (!mp->enabled) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } + + spin_unlock_irqrestore(&data_lock, flags); r = dispc_runtime_get(); if (r) @@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) op = get_ovl_priv(ovl); i = 0; while (1) { - unsigned long flags; bool shadow_dirty, dirty; spin_lock_irqsave(&data_lock, flags); @@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); - r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings); + r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); if (r) { /* * We can't do much here, as this function can be called from @@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) mp->shadow_extra_info_dirty = true; } -static void dss_write_regs_common(void) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - int i; - - if (!dss_data.fifo_merge_dirty) - return; - - for (i = 0; i < num_mgrs; ++i) { - struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; - - mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (mp->enabled) { - if (dss_data.fifo_merge_dirty) { - dispc_enable_fifomerge(dss_data.fifo_merge); - dss_data.fifo_merge_dirty = false; - } - - if (mp->updating) - mp->shadow_info_dirty = true; - } - } -} - static void dss_write_regs(void) { const int num_mgrs = omap_dss_get_num_overlay_managers(); int i; - dss_write_regs_common(); - for (i = 0; i < num_mgrs; ++i) { struct omap_overlay_manager *mgr; struct mgr_priv_data *mp; @@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) dss_mgr_write_regs(mgr); dss_mgr_write_regs_extra(mgr); - dss_write_regs_common(); - mp->updating = true; if (!dss_data.irq_enabled && need_isr()) @@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, op->extra_info_dirty = true; } -static void dss_apply_fifo_merge(bool use_fifo_merge) -{ - if (dss_data.fifo_merge == use_fifo_merge) - return; - - dss_data.fifo_merge = use_fifo_merge; - dss_data.fifo_merge_dirty = true; -} - -static void dss_ovl_setup_fifo(struct omap_overlay *ovl, - bool use_fifo_merge) +static void dss_ovl_setup_fifo(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); u32 fifo_low, fifo_high; + bool use_fifo_merge = false; if (!op->enabled && !op->enabling) return; @@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl, dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); } -static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, - bool use_fifo_merge) +static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) { struct omap_overlay *ovl; struct mgr_priv_data *mp; @@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, return; list_for_each_entry(ovl, &mgr->overlays, list) - dss_ovl_setup_fifo(ovl, use_fifo_merge); -} - -static void dss_setup_fifos(bool use_fifo_merge) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - struct omap_overlay_manager *mgr; - int i; - - for (i = 0; i < num_mgrs; ++i) { - mgr = omap_dss_get_overlay_manager(i); - dss_mgr_setup_fifos(mgr, use_fifo_merge); - } + dss_ovl_setup_fifo(ovl); } -static int get_num_used_managers(void) +static void dss_setup_fifos(void) { const int num_mgrs = omap_dss_get_num_overlay_managers(); struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; int i; - int enabled_mgrs; - - enabled_mgrs = 0; for (i = 0; i < num_mgrs; ++i) { mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - continue; - - enabled_mgrs++; + dss_mgr_setup_fifos(mgr); } - - return enabled_mgrs; -} - -static int get_num_used_overlays(void) -{ - const int num_ovls = omap_dss_get_num_overlays(); - struct omap_overlay *ovl; - struct ovl_priv_data *op; - struct mgr_priv_data *mp; - int i; - int enabled_ovls; - - enabled_ovls = 0; - - for (i = 0; i < num_ovls; ++i) { - ovl = omap_dss_get_overlay(i); - op = get_ovl_priv(ovl); - - if (!op->enabled && !op->enabling) - continue; - - mp = get_mgr_priv(ovl->manager); - - if (!mp->enabled) - continue; - - enabled_ovls++; - } - - return enabled_ovls; -} - -static bool get_use_fifo_merge(void) -{ - int enabled_mgrs = get_num_used_managers(); - int enabled_ovls = get_num_used_overlays(); - - if (!dss_has_feature(FEAT_FIFO_MERGE)) - return false; - - /* - * In theory the only requirement for fifomerge is enabled_ovls <= 1. - * However, if we have two managers enabled and set/unset the fifomerge, - * we need to set the GO bits in particular sequence for the managers, - * and wait in between. - * - * This is rather difficult as new apply calls can happen at any time, - * so we simplify the problem by requiring also that enabled_mgrs <= 1. - * In practice this shouldn't matter, because when only one overlay is - * enabled, most likely only one output is enabled. - */ - - return enabled_mgrs <= 1 && enabled_ovls <= 1; } int dss_mgr_enable(struct omap_overlay_manager *mgr) @@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; int r; - bool fifo_merge; mutex_lock(&apply_lock); @@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) goto err; } - /* step 1: setup fifos/fifomerge before enabling the manager */ - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); + dss_setup_fifos(); dss_write_regs(); dss_set_go_bits(); - spin_unlock_irqrestore(&data_lock, flags); - - /* wait until fifo config is in */ - wait_pending_extra_info_updates(); - - /* step 2: enable the manager */ - spin_lock_irqsave(&data_lock, flags); - if (!mgr_manual_update(mgr)) mp->updating = true; @@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; - bool fifo_merge; mutex_lock(&apply_lock); @@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) mp->updating = false; mp->enabled = false; - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - spin_unlock_irqrestore(&data_lock, flags); - wait_pending_extra_info_updates(); out: mutex_unlock(&apply_lock); } @@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, spin_unlock_irqrestore(&data_lock, flags); } -int dss_mgr_set_device(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev) +int dss_mgr_set_output(struct omap_overlay_manager *mgr, + struct omap_dss_output *output) { int r; mutex_lock(&apply_lock); - if (dssdev->manager) { - DSSERR("display '%s' already has a manager '%s'\n", - dssdev->name, dssdev->manager->name); + if (mgr->output) { + DSSERR("manager %s is already connected to an output\n", + mgr->name); r = -EINVAL; goto err; } - if ((mgr->supported_displays & dssdev->type) == 0) { - DSSERR("display '%s' does not support manager '%s'\n", - dssdev->name, mgr->name); + if ((mgr->supported_outputs & output->id) == 0) { + DSSERR("output does not support manager %s\n", + mgr->name); r = -EINVAL; goto err; } - dssdev->manager = mgr; - mgr->device = dssdev; + output->manager = mgr; + mgr->output = output; mutex_unlock(&apply_lock); @@ -1269,40 +1142,46 @@ err: return r; } -int dss_mgr_unset_device(struct omap_overlay_manager *mgr) +int dss_mgr_unset_output(struct omap_overlay_manager *mgr) { int r; + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; mutex_lock(&apply_lock); - if (!mgr->device) { - DSSERR("failed to unset display, display not set.\n"); + if (!mgr->output) { + DSSERR("failed to unset output, output not set\n"); r = -EINVAL; goto err; } - /* - * Don't allow currently enabled displays to have the overlay manager - * pulled out from underneath them - */ - if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { + spin_lock_irqsave(&data_lock, flags); + + if (mp->enabled) { + DSSERR("output can't be unset when manager is enabled\n"); r = -EINVAL; - goto err; + goto err1; } - mgr->device->manager = NULL; - mgr->device = NULL; + spin_unlock_irqrestore(&data_lock, flags); + + mgr->output->manager = NULL; + mgr->output = NULL; mutex_unlock(&apply_lock); return 0; +err1: + spin_unlock_irqrestore(&data_lock, flags); err: mutex_unlock(&apply_lock); + return r; } static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, } void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { unsigned long flags; - - mutex_lock(&apply_lock); + struct mgr_priv_data *mp = get_mgr_priv(mgr); spin_lock_irqsave(&data_lock, flags); - dss_apply_mgr_timings(mgr, timings); - - dss_write_regs(); - dss_set_go_bits(); + if (mp->updating) { + DSSERR("cannot set timings for %s: manager needs to be disabled\n", + mgr->name); + goto out; + } + dss_apply_mgr_timings(mgr, timings); +out: spin_unlock_irqrestore(&data_lock, flags); - - wait_pending_extra_info_updates(); - - mutex_unlock(&apply_lock); } static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, @@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, unsigned long flags; struct mgr_priv_data *mp = get_mgr_priv(mgr); - mutex_lock(&apply_lock); + spin_lock_irqsave(&data_lock, flags); if (mp->enabled) { DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", @@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, goto out; } - spin_lock_irqsave(&data_lock, flags); - dss_apply_mgr_lcd_config(mgr, config); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - wait_pending_extra_info_updates(); - out: - mutex_unlock(&apply_lock); + spin_unlock_irqrestore(&data_lock, flags); } int dss_ovl_set_info(struct omap_overlay *ovl, @@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) goto err; } + spin_unlock_irqrestore(&data_lock, flags); + + /* wait for pending extra_info updates to ensure the ovl is disabled */ + wait_pending_extra_info_updates(); + + spin_lock_irqsave(&data_lock, flags); + op->channel = -1; ovl->manager = NULL; @@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; - bool fifo_merge; int r; mutex_lock(&apply_lock); @@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) goto err1; } - if (ovl->manager == NULL || ovl->manager->device == NULL) { + if (ovl->manager == NULL || ovl->manager->output == NULL) { r = -EINVAL; goto err1; } @@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) goto err2; } - /* step 1: configure fifos/fifomerge for currently enabled ovls */ - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - /* wait for fifo configs to go in */ - wait_pending_extra_info_updates(); - - /* step 2: enable the overlay */ - spin_lock_irqsave(&data_lock, flags); + dss_setup_fifos(); op->enabling = false; dss_apply_ovl_enable(ovl, true); @@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) spin_unlock_irqrestore(&data_lock, flags); - /* wait for overlay to be enabled */ - wait_pending_extra_info_updates(); - mutex_unlock(&apply_lock); return 0; @@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; - bool fifo_merge; int r; mutex_lock(&apply_lock); @@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl) goto err; } - if (ovl->manager == NULL || ovl->manager->device == NULL) { + if (ovl->manager == NULL || ovl->manager->output == NULL) { r = -EINVAL; goto err; } - /* step 1: disable the overlay */ spin_lock_irqsave(&data_lock, flags); dss_apply_ovl_enable(ovl, false); - dss_write_regs(); dss_set_go_bits(); spin_unlock_irqrestore(&data_lock, flags); - /* wait for the overlay to be disabled */ - wait_pending_extra_info_updates(); - - /* step 2: configure fifos/fifomerge */ - spin_lock_irqsave(&data_lock, flags); - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - /* wait for fifo config to go in */ - wait_pending_extra_info_updates(); - mutex_unlock(&apply_lock); return 0; diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 58bd9c27369d..b2af72dc20bd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -33,6 +33,7 @@ #include <linux/device.h> #include <linux/regulator/consumer.h> #include <linux/suspend.h> +#include <linux/slab.h> #include <video/omapdss.h> @@ -57,6 +58,11 @@ bool dss_debug; module_param_named(debug, dss_debug, bool, 0644); #endif +const char *dss_get_default_display_name(void) +{ + return core.default_display_name; +} + /* REGULATORS */ struct regulator *dss_get_vdds_dsi(void) @@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev) int r; struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); struct omap_dss_device *dssdev = to_dss_device(dev); - bool force; DSSDBG("driver_probe: dev %s/%s, drv %s\n", dev_name(dev), dssdev->driver_name, dssdrv->driver.name); - dss_init_device(core.pdev, dssdev); - - force = core.default_display_name && - strcmp(core.default_display_name, dssdev->name) == 0; - dss_recheck_connections(dssdev, force); + r = dss_init_device(core.pdev, dssdev); + if (r) + return r; r = dssdrv->probe(dssdev); @@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) EXPORT_SYMBOL(omap_dss_unregister_driver); /* DEVICE */ -static void reset_device(struct device *dev, int check) -{ - u8 *dev_p = (u8 *)dev; - u8 *dev_end = dev_p + sizeof(*dev); - void *saved_pdata; - - saved_pdata = dev->platform_data; - if (check) { - /* - * Check if there is any other setting than platform_data - * in struct device; warn that these will be reset by our - * init. - */ - dev->platform_data = NULL; - while (dev_p < dev_end) { - if (*dev_p) { - WARN("%s: struct device fields will be " - "discarded\n", - __func__); - break; - } - dev_p++; - } - } - memset(dev, 0, sizeof(*dev)); - dev->platform_data = saved_pdata; -} - static void omap_dss_dev_release(struct device *dev) { - reset_device(dev, 0); + struct omap_dss_device *dssdev = to_dss_device(dev); + kfree(dssdev); } -int omap_dss_register_device(struct omap_dss_device *dssdev, - struct device *parent, int disp_num) +static int disp_num_counter; + +struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) { - WARN_ON(!dssdev->driver_name); + struct omap_dss_device *dssdev; + + dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); + if (!dssdev) + return NULL; - reset_device(&dssdev->dev, 1); dssdev->dev.bus = &dss_bus_type; dssdev->dev.parent = parent; dssdev->dev.release = omap_dss_dev_release; - dev_set_name(&dssdev->dev, "display%d", disp_num); - return device_register(&dssdev->dev); + dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); + + device_initialize(&dssdev->dev); + + return dssdev; +} + +int dss_add_device(struct omap_dss_device *dssdev) +{ + return device_add(&dssdev->dev); +} + +void dss_put_device(struct omap_dss_device *dssdev) +{ + put_device(&dssdev->dev); } -void omap_dss_unregister_device(struct omap_dss_device *dssdev) +void dss_unregister_device(struct omap_dss_device *dssdev) { device_unregister(&dssdev->dev); } @@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev) static int dss_unregister_dss_dev(struct device *dev, void *data) { struct omap_dss_device *dssdev = to_dss_device(dev); - omap_dss_unregister_device(dssdev); + dss_unregister_device(dssdev); return 0; } -void omap_dss_unregister_child_devices(struct device *parent) +void dss_unregister_child_devices(struct device *parent) { device_for_each_child(parent, NULL, dss_unregister_dss_dev); } +void dss_copy_device_pdata(struct omap_dss_device *dst, + const struct omap_dss_device *src) +{ + u8 *d = (u8 *)dst; + u8 *s = (u8 *)src; + size_t dsize = sizeof(struct device); + + memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); +} + /* BUS */ static int __init omap_dss_bus_register(void) { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee9e29639dcc..b43477a5fae8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -38,7 +38,6 @@ #include <linux/pm_runtime.h> #include <plat/cpu.h> -#include <plat/clock.h> #include <video/omapdss.h> @@ -82,6 +81,30 @@ struct dispc_irq_stats { unsigned irqs[32]; }; +struct dispc_features { + u8 sw_start; + u8 fp_start; + u8 bp_start; + u16 sw_max; + u16 vp_max; + u16 hp_max; + int (*calc_scaling) (enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem); + unsigned long (*calc_core_clk) (enum omap_plane plane, + u16 width, u16 height, u16 out_width, u16 out_height, + bool mem_to_mem); + u8 num_fifos; + + /* swap GFX & WB fifos */ + bool gfx_fifo_workaround:1; +}; + +#define DISPC_MAX_NR_FIFOS 5 + static struct { struct platform_device *pdev; void __iomem *base; @@ -91,7 +114,9 @@ static struct { int irq; struct clk *dss_clk; - u32 fifo_size[MAX_DSS_OVERLAYS]; + u32 fifo_size[DISPC_MAX_NR_FIFOS]; + /* maps which plane is using a fifo. fifo-id -> plane-id */ + int fifo_assignment[DISPC_MAX_NR_FIFOS]; spinlock_t irq_lock; u32 irq_error_mask; @@ -102,6 +127,8 @@ static struct { bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + const struct dispc_features *feat; + #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spinlock_t irq_stats_lock; struct dispc_irq_stats irq_stats; @@ -211,7 +238,14 @@ static const struct { }, }; +struct color_conv_coef { + int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; + int full_range; +}; + static void _omap_dispc_set_irqs(void); +static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); +static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); static inline void dispc_write_reg(const u16 idx, u32 val) { @@ -509,6 +543,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) return mgr_desc[channel].framedone_irq; } +u32 dispc_wb_get_framedone_irq(void) +{ + return DISPC_IRQ_FRAMEDONEWB; +} + bool dispc_mgr_go_busy(enum omap_channel channel) { return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; @@ -536,6 +575,30 @@ void dispc_mgr_go(enum omap_channel channel) mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); } +bool dispc_wb_go_busy(void) +{ + return REG_GET(DISPC_CONTROL2, 6, 6) == 1; +} + +void dispc_wb_go(void) +{ + enum omap_plane plane = OMAP_DSS_WB; + bool enable, go; + + enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; + + if (!enable) + return; + + go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; + if (go) { + DSSERR("GO bit not down for WB\n"); + return; + } + + REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); +} + static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) { dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); @@ -618,41 +681,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, } } -static void _dispc_setup_color_conv_coef(void) -{ - int i; - const struct color_conv_coef { - int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; - int full_range; - } ctbl_bt601_5 = { - 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, - }; - - const struct color_conv_coef *ct; +static void dispc_ovl_write_color_conv_coef(enum omap_plane plane, + const struct color_conv_coef *ct) +{ #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) - ct = &ctbl_bt601_5; + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); - for (i = 1; i < dss_feat_get_num_ovls(); i++) { - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), - CVAL(0, ct->bcb)); - - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, - 11, 11); - } + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); #undef CVAL } +static void dispc_setup_color_conv_coef(void) +{ + int i; + int num_ovl = dss_feat_get_num_ovls(); + int num_wb = dss_feat_get_num_wbs(); + const struct color_conv_coef ctbl_bt601_5_ovl = { + 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, + }; + const struct color_conv_coef ctbl_bt601_5_wb = { + 66, 112, -38, 129, -94, -74, 25, -18, 112, 0, + }; + + for (i = 1; i < num_ovl; i++) + dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); + + for (; i < num_wb; i++) + dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb); +} static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) { @@ -674,24 +737,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); } -static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) +static void dispc_ovl_set_pos(enum omap_plane plane, + enum omap_overlay_caps caps, int x, int y) { - u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); + u32 val; + + if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) + return; + + val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); dispc_write_reg(DISPC_OVL_POSITION(plane), val); } -static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_input_size(enum omap_plane plane, int width, + int height) { u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - if (plane == OMAP_DSS_GFX) + if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) dispc_write_reg(DISPC_OVL_SIZE(plane), val); else dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); } -static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_output_size(enum omap_plane plane, int width, + int height) { u32 val; @@ -699,14 +770,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + if (plane == OMAP_DSS_WB) + dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + else + dispc_write_reg(DISPC_OVL_SIZE(plane), val); } -static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) +static void dispc_ovl_set_zorder(enum omap_plane plane, + enum omap_overlay_caps caps, u8 zorder) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) return; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); @@ -723,23 +796,22 @@ static void dispc_ovl_enable_zorder_planes(void) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } -static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) +static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, + enum omap_overlay_caps caps, bool enable) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) return; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); } -static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) +static void dispc_ovl_setup_global_alpha(enum omap_plane plane, + enum omap_overlay_caps caps, u8 global_alpha) { static const unsigned shifts[] = { 0, 8, 16, 24, }; int shift; - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) + if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) return; shift = shifts[plane]; @@ -947,10 +1019,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) return channel; } +void dispc_wb_set_channel_in(enum dss_writeback_channel channel) +{ + enum omap_plane plane = OMAP_DSS_WB; + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); +} + static void dispc_ovl_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { - static const unsigned shifts[] = { 6, 14, 14, 14, }; + static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; int shift; shift = shifts[plane]; @@ -1027,11 +1106,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } -static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) +static void dispc_ovl_enable_replication(enum omap_plane plane, + enum omap_overlay_caps caps, bool enable) { static const unsigned shifts[] = { 5, 10, 10, 10 }; int shift; + if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) + return; + shift = shifts[plane]; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); } @@ -1045,10 +1128,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, dispc_write_reg(DISPC_SIZE_MGR(channel), val); } -static void dispc_read_plane_fifo_sizes(void) +static void dispc_init_fifos(void) { u32 size; - int plane; + int fifo; u8 start, end; u32 unit; @@ -1056,16 +1139,53 @@ static void dispc_read_plane_fifo_sizes(void) dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); - for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { - size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); + for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { + size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); size *= unit; - dispc.fifo_size[plane] = size; + dispc.fifo_size[fifo] = size; + + /* + * By default fifos are mapped directly to overlays, fifo 0 to + * ovl 0, fifo 1 to ovl 1, etc. + */ + dispc.fifo_assignment[fifo] = fifo; + } + + /* + * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo + * causes problems with certain use cases, like using the tiler in 2D + * mode. The below hack swaps the fifos of GFX and WB planes, thus + * giving GFX plane a larger fifo. WB but should work fine with a + * smaller fifo. + */ + if (dispc.feat->gfx_fifo_workaround) { + u32 v; + + v = dispc_read_reg(DISPC_GLOBAL_BUFFER); + + v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ + v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ + v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ + v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ + + dispc_write_reg(DISPC_GLOBAL_BUFFER, v); + + dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; + dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; } } static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) { - return dispc.fifo_size[plane]; + int fifo; + u32 size = 0; + + for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { + if (dispc.fifo_assignment[fifo] == plane) + size += dispc.fifo_size[fifo]; + } + + return size; } void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) @@ -1141,6 +1261,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { *fifo_low = ovl_fifo_size - burst_size * 2; *fifo_high = total_fifo_size - burst_size; + } else if (plane == OMAP_DSS_WB) { + /* + * Most optimal configuration for writeback is to push out data + * to the interconnect the moment writeback pushes enough pixels + * in the FIFO to form a burst + */ + *fifo_low = 0; + *fifo_high = burst_size; } else { *fifo_low = ovl_fifo_size - burst_size; *fifo_high = total_fifo_size - buf_unit; @@ -1383,6 +1511,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, { int scale_x = out_width != orig_width; int scale_y = out_height != orig_height; + bool chroma_upscale = plane != OMAP_DSS_WB ? true : false; if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) return; @@ -1390,7 +1519,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, color_mode != OMAP_DSS_COLOR_UYVY && color_mode != OMAP_DSS_COLOR_NV12)) { /* reset chroma resampling for RGB formats */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); + if (plane != OMAP_DSS_WB) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); return; } @@ -1399,23 +1529,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, switch (color_mode) { case OMAP_DSS_COLOR_NV12: - /* UV is subsampled by 2 vertically*/ - orig_height >>= 1; - /* UV is subsampled by 2 horz.*/ - orig_width >>= 1; + if (chroma_upscale) { + /* UV is subsampled by 2 horizontally and vertically */ + orig_height >>= 1; + orig_width >>= 1; + } else { + /* UV is downsampled by 2 horizontally and vertically */ + orig_height <<= 1; + orig_width <<= 1; + } + break; case OMAP_DSS_COLOR_YUV2: case OMAP_DSS_COLOR_UYVY: - /*For YUV422 with 90/270 rotation, - *we don't upsample chroma - */ + /* For YUV422 with 90/270 rotation, we don't upsample chroma */ if (rotation == OMAP_DSS_ROT_0 || - rotation == OMAP_DSS_ROT_180) - /* UV is subsampled by 2 hrz*/ - orig_width >>= 1; + rotation == OMAP_DSS_ROT_180) { + if (chroma_upscale) + /* UV is subsampled by 2 horizontally */ + orig_width >>= 1; + else + /* UV is downsampled by 2 horizontally */ + orig_width <<= 1; + } + /* must use FIR for YUV422 if rotated */ if (rotation != OMAP_DSS_ROT_0) scale_x = scale_y = true; + break; default: BUG(); @@ -1431,8 +1572,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_UV); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), - (scale_x || scale_y) ? 1 : 0, 8, 8); + if (plane != OMAP_DSS_WB) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), + (scale_x || scale_y) ? 1 : 0, 8, 8); + /* set H scaling */ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); /* set V scaling */ @@ -1848,22 +1991,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, * This function is used to avoid synclosts in OMAP3, because of some * undocumented horizontal position and timing related limitations. */ -static int check_horiz_timing_omap3(enum omap_channel channel, +static int check_horiz_timing_omap3(enum omap_plane plane, const struct omap_video_timings *t, u16 pos_x, u16 width, u16 height, u16 out_width, u16 out_height) { int DS = DIV_ROUND_UP(height, out_height); - unsigned long nonactive, lclk, pclk; + unsigned long nonactive; static const u8 limits[3] = { 8, 10, 20 }; u64 val, blank; + unsigned long pclk = dispc_plane_pclk_rate(plane); + unsigned long lclk = dispc_plane_lclk_rate(plane); int i; nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; - pclk = dispc_mgr_pclk_rate(channel); - if (dss_mgr_is_lcd(channel)) - lclk = dispc_mgr_lclk_rate(channel); - else - lclk = dispc_fclk_rate(); i = 0; if (out_height < height) @@ -1900,13 +2040,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel, return 0; } -static unsigned long calc_core_clk_five_taps(enum omap_channel channel, +static unsigned long calc_core_clk_five_taps(enum omap_plane plane, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode) { u32 core_clk = 0; - u64 tmp, pclk = dispc_mgr_pclk_rate(channel); + u64 tmp; + unsigned long pclk = dispc_plane_pclk_rate(plane); if (height <= out_height && width <= out_width) return (unsigned long) pclk; @@ -1940,11 +2081,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel, return core_clk; } -static unsigned long calc_core_clk(enum omap_channel channel, u16 width, - u16 height, u16 out_width, u16 out_height) +static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) +{ + unsigned long pclk = dispc_plane_pclk_rate(plane); + + if (height > out_height && width > out_width) + return pclk * 4; + else + return pclk * 2; +} + +static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) { unsigned int hf, vf; - unsigned long pclk = dispc_mgr_pclk_rate(channel); + unsigned long pclk = dispc_plane_pclk_rate(plane); /* * FIXME how to determine the 'A' factor @@ -1959,51 +2111,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width, hf = 2; else hf = 1; - if (height > out_height) vf = 2; else vf = 1; - if (cpu_is_omap24xx()) { - if (vf > 1 && hf > 1) - return pclk * 4; - else - return pclk * 2; - } else if (cpu_is_omap34xx()) { - return pclk * vf * hf; - } else { - if (hf > 1) - return DIV_ROUND_UP(pclk, out_width) * width; - else - return pclk; + return pclk * vf * hf; +} + +static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) +{ + unsigned long pclk; + + /* + * If the overlay/writeback is in mem to mem mode, there are no + * downscaling limitations with respect to pixel clock, return 1 as + * required core clock to represent that we have sufficient enough + * core clock to do maximum downscaling + */ + if (mem_to_mem) + return 1; + + pclk = dispc_plane_pclk_rate(plane); + + if (width > out_width) + return DIV_ROUND_UP(pclk, out_width) * width; + else + return pclk; +} + +static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +{ + int error; + u16 in_width, in_height; + int min_factor = min(*decim_x, *decim_y); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + + *five_taps = false; + + do { + in_height = DIV_ROUND_UP(height, *decim_y); + in_width = DIV_ROUND_UP(width, *decim_x); + *core_clk = dispc.feat->calc_core_clk(plane, in_width, + in_height, out_width, out_height, mem_to_mem); + error = (in_width > maxsinglelinewidth || !*core_clk || + *core_clk > dispc_core_clk_rate()); + if (error) { + if (*decim_x == *decim_y) { + *decim_x = min_factor; + ++*decim_y; + } else { + swap(*decim_x, *decim_y); + if (*decim_x < *decim_y) + ++*decim_x; + } + } + } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + + if (in_width > maxsinglelinewidth) { + DSSERR("Cannot scale max input width exceeded"); + return -EINVAL; } + return 0; } -static int dispc_ovl_calc_scaling(enum omap_plane plane, - enum omap_channel channel, +static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, - int *x_predecim, int *y_predecim, u16 pos_x) + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + int error; + u16 in_width, in_height; + int min_factor = min(*decim_x, *decim_y); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + + do { + in_height = DIV_ROUND_UP(height, *decim_y); + in_width = DIV_ROUND_UP(width, *decim_x); + *core_clk = calc_core_clk_five_taps(plane, mgr_timings, + in_width, in_height, out_width, out_height, color_mode); + + error = check_horiz_timing_omap3(plane, mgr_timings, + pos_x, in_width, in_height, out_width, + out_height); + + if (in_width > maxsinglelinewidth) + if (in_height > out_height && + in_height < out_height * 2) + *five_taps = false; + if (!*five_taps) + *core_clk = dispc.feat->calc_core_clk(plane, in_width, + in_height, out_width, out_height, + mem_to_mem); + + error = (error || in_width > maxsinglelinewidth * 2 || + (in_width > maxsinglelinewidth && *five_taps) || + !*core_clk || *core_clk > dispc_core_clk_rate()); + if (error) { + if (*decim_x == *decim_y) { + *decim_x = min_factor; + ++*decim_y; + } else { + swap(*decim_x, *decim_y); + if (*decim_x < *decim_y) + ++*decim_x; + } + } + } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + + if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, + out_width, out_height)){ + DSSERR("horizontal timing too tight\n"); + return -EINVAL; + } + + if (in_width > (maxsinglelinewidth * 2)) { + DSSERR("Cannot setup scaling"); + DSSERR("width exceeds maximum width possible"); + return -EINVAL; + } + + if (in_width > maxsinglelinewidth && *five_taps) { + DSSERR("cannot setup scaling with five taps"); + return -EINVAL; + } + return 0; +} + +static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +{ + u16 in_width, in_width_max; + int decim_x_min = *decim_x; + u16 in_height = DIV_ROUND_UP(height, *decim_y); const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + unsigned long pclk = dispc_plane_pclk_rate(plane); + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + + if (mem_to_mem) + in_width_max = DIV_ROUND_UP(out_width, maxdownscale); + else + in_width_max = dispc_core_clk_rate() / + DIV_ROUND_UP(pclk, out_width); + + *decim_x = DIV_ROUND_UP(width, in_width_max); + + *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; + if (*decim_x > *x_predecim) + return -EINVAL; + + do { + in_width = DIV_ROUND_UP(width, *decim_x); + } while (*decim_x <= *x_predecim && + in_width > maxsinglelinewidth && ++*decim_x); + + if (in_width > maxsinglelinewidth) { + DSSERR("Cannot scale width exceeds max line width"); + return -EINVAL; + } + + *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, + out_width, out_height, mem_to_mem); + return 0; +} + +static int dispc_ovl_calc_scaling(enum omap_plane plane, + enum omap_overlay_caps caps, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, u16 pos_x, + enum omap_dss_rotation_type rotation_type, bool mem_to_mem) +{ + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); const int max_decim_limit = 16; unsigned long core_clk = 0; - int decim_x, decim_y, error, min_factor; - u16 in_width, in_height, in_width_max = 0; + int decim_x, decim_y, ret; if (width == out_width && height == out_height) return 0; - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) + if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) return -EINVAL; *x_predecim = max_decim_limit; - *y_predecim = max_decim_limit; + *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && + dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; if (color_mode == OMAP_DSS_COLOR_CLUT1 || color_mode == OMAP_DSS_COLOR_CLUT2 || @@ -2018,118 +2326,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); - min_factor = min(decim_x, decim_y); - if (decim_x > *x_predecim || out_width > width * 8) return -EINVAL; if (decim_y > *y_predecim || out_height > height * 8) return -EINVAL; - if (cpu_is_omap24xx()) { - *five_taps = false; - - do { - in_height = DIV_ROUND_UP(height, decim_y); - in_width = DIV_ROUND_UP(width, decim_x); - core_clk = calc_core_clk(channel, in_width, in_height, - out_width, out_height); - error = (in_width > maxsinglelinewidth || !core_clk || - core_clk > dispc_core_clk_rate()); - if (error) { - if (decim_x == decim_y) { - decim_x = min_factor; - decim_y++; - } else { - swap(decim_x, decim_y); - if (decim_x < decim_y) - decim_x++; - } - } - } while (decim_x <= *x_predecim && decim_y <= *y_predecim && - error); - - if (in_width > maxsinglelinewidth) { - DSSERR("Cannot scale max input width exceeded"); - return -EINVAL; - } - } else if (cpu_is_omap34xx()) { - - do { - in_height = DIV_ROUND_UP(height, decim_y); - in_width = DIV_ROUND_UP(width, decim_x); - core_clk = calc_core_clk_five_taps(channel, mgr_timings, - in_width, in_height, out_width, out_height, - color_mode); - - error = check_horiz_timing_omap3(channel, mgr_timings, - pos_x, in_width, in_height, out_width, - out_height); - - if (in_width > maxsinglelinewidth) - if (in_height > out_height && - in_height < out_height * 2) - *five_taps = false; - if (!*five_taps) - core_clk = calc_core_clk(channel, in_width, - in_height, out_width, out_height); - error = (error || in_width > maxsinglelinewidth * 2 || - (in_width > maxsinglelinewidth && *five_taps) || - !core_clk || core_clk > dispc_core_clk_rate()); - if (error) { - if (decim_x == decim_y) { - decim_x = min_factor; - decim_y++; - } else { - swap(decim_x, decim_y); - if (decim_x < decim_y) - decim_x++; - } - } - } while (decim_x <= *x_predecim && decim_y <= *y_predecim - && error); - - if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, - height, out_width, out_height)){ - DSSERR("horizontal timing too tight\n"); - return -EINVAL; - } - - if (in_width > (maxsinglelinewidth * 2)) { - DSSERR("Cannot setup scaling"); - DSSERR("width exceeds maximum width possible"); - return -EINVAL; - } - - if (in_width > maxsinglelinewidth && *five_taps) { - DSSERR("cannot setup scaling with five taps"); - return -EINVAL; - } - } else { - int decim_x_min = decim_x; - in_height = DIV_ROUND_UP(height, decim_y); - in_width_max = dispc_core_clk_rate() / - DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), - out_width); - decim_x = DIV_ROUND_UP(width, in_width_max); - - decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; - if (decim_x > *x_predecim) - return -EINVAL; - - do { - in_width = DIV_ROUND_UP(width, decim_x); - } while (decim_x <= *x_predecim && - in_width > maxsinglelinewidth && decim_x++); - - if (in_width > maxsinglelinewidth) { - DSSERR("Cannot scale width exceeds max line width"); - return -EINVAL; - } - - core_clk = calc_core_clk(channel, in_width, in_height, - out_width, out_height); - } + ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, + out_width, out_height, color_mode, five_taps, + x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, + mem_to_mem); + if (ret) + return ret; DSSDBG("required core clk rate = %lu Hz\n", core_clk); DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); @@ -2147,69 +2355,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, return 0; } -int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings) +static int dispc_ovl_setup_common(enum omap_plane plane, + enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, + u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, + u16 out_width, u16 out_height, enum omap_color_mode color_mode, + u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha, + u8 global_alpha, enum omap_dss_rotation_type rotation_type, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); bool five_taps = true; bool fieldmode = 0; int r, cconv = 0; unsigned offset0, offset1; s32 row_inc; s32 pix_inc; - u16 frame_height = oi->height; + u16 frame_height = height; unsigned int field_offset = 0; - u16 in_height = oi->height; - u16 in_width = oi->width; - u16 out_width, out_height; - enum omap_channel channel; + u16 in_height = height; + u16 in_width = width; int x_predecim = 1, y_predecim = 1; bool ilace = mgr_timings->interlace; - channel = dispc_ovl_get_channel_out(plane); - - DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", - plane, oi->paddr, oi->p_uv_addr, - oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, - oi->out_width, oi->out_height, oi->color_mode, oi->rotation, - oi->mirror, ilace, channel, replication); - - if (oi->paddr == 0) + if (paddr == 0) return -EINVAL; - out_width = oi->out_width == 0 ? oi->width : oi->out_width; - out_height = oi->out_height == 0 ? oi->height : oi->out_height; + out_width = out_width == 0 ? width : out_width; + out_height = out_height == 0 ? height : out_height; - if (ilace && oi->height == out_height) + if (ilace && height == out_height) fieldmode = 1; if (ilace) { if (fieldmode) in_height /= 2; - oi->pos_y /= 2; + pos_y /= 2; out_height /= 2; DSSDBG("adjusting for ilace: height %d, pos_y %d, " - "out_height %d\n", - in_height, oi->pos_y, out_height); + "out_height %d\n", in_height, pos_y, + out_height); } - if (!dss_feat_color_mode_supported(plane, oi->color_mode)) + if (!dss_feat_color_mode_supported(plane, color_mode)) return -EINVAL; - r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, - in_height, out_width, out_height, oi->color_mode, - &five_taps, &x_predecim, &y_predecim, oi->pos_x); + r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, + in_height, out_width, out_height, color_mode, + &five_taps, &x_predecim, &y_predecim, pos_x, + rotation_type, mem_to_mem); if (r) return r; in_width = DIV_ROUND_UP(in_width, x_predecim); in_height = DIV_ROUND_UP(in_height, y_predecim); - if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || - oi->color_mode == OMAP_DSS_COLOR_UYVY || - oi->color_mode == OMAP_DSS_COLOR_NV12) + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY || + color_mode == OMAP_DSS_COLOR_NV12) cconv = 1; if (ilace && !fieldmode) { @@ -2235,70 +2438,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, row_inc = 0; pix_inc = 0; - if (oi->rotation_type == OMAP_DSS_ROT_TILER) - calc_tiler_rotation_offset(oi->screen_width, in_width, - oi->color_mode, fieldmode, field_offset, + if (rotation_type == OMAP_DSS_ROT_TILER) + calc_tiler_rotation_offset(screen_width, in_width, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); - else if (oi->rotation_type == OMAP_DSS_ROT_DMA) - calc_dma_rotation_offset(oi->rotation, oi->mirror, - oi->screen_width, in_width, frame_height, - oi->color_mode, fieldmode, field_offset, + else if (rotation_type == OMAP_DSS_ROT_DMA) + calc_dma_rotation_offset(rotation, mirror, + screen_width, in_width, frame_height, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); else - calc_vrfb_rotation_offset(oi->rotation, oi->mirror, - oi->screen_width, in_width, frame_height, - oi->color_mode, fieldmode, field_offset, + calc_vrfb_rotation_offset(rotation, mirror, + screen_width, in_width, frame_height, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); - dispc_ovl_set_color_mode(plane, oi->color_mode); + dispc_ovl_set_color_mode(plane, color_mode); - dispc_ovl_configure_burst_type(plane, oi->rotation_type); + dispc_ovl_configure_burst_type(plane, rotation_type); - dispc_ovl_set_ba0(plane, oi->paddr + offset0); - dispc_ovl_set_ba1(plane, oi->paddr + offset1); + dispc_ovl_set_ba0(plane, paddr + offset0); + dispc_ovl_set_ba1(plane, paddr + offset1); - if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { - dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); - dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); + if (OMAP_DSS_COLOR_NV12 == color_mode) { + dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); + dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); } - dispc_ovl_set_row_inc(plane, row_inc); dispc_ovl_set_pix_inc(plane, pix_inc); - DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, + DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, in_height, out_width, out_height); - dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); + dispc_ovl_set_pos(plane, caps, pos_x, pos_y); - dispc_ovl_set_pic_size(plane, in_width, in_height); + dispc_ovl_set_input_size(plane, in_width, in_height); - if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { + if (caps & OMAP_DSS_OVL_CAP_SCALE) { dispc_ovl_set_scaling(plane, in_width, in_height, out_width, out_height, ilace, five_taps, fieldmode, - oi->color_mode, oi->rotation); - dispc_ovl_set_vid_size(plane, out_width, out_height); + color_mode, rotation); + dispc_ovl_set_output_size(plane, out_width, out_height); dispc_ovl_set_vid_color_conv(plane, cconv); } - dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, - oi->color_mode); + dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); - dispc_ovl_set_zorder(plane, oi->zorder); - dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); - dispc_ovl_setup_global_alpha(plane, oi->global_alpha); + dispc_ovl_set_zorder(plane, caps, zorder); + dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); + dispc_ovl_setup_global_alpha(plane, caps, global_alpha); - dispc_ovl_enable_replication(plane, replication); + dispc_ovl_enable_replication(plane, caps, replication); return 0; } +int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem) +{ + int r; + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + enum omap_channel channel; + + channel = dispc_ovl_get_channel_out(plane); + + DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " + "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", + plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, + oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, + oi->color_mode, oi->rotation, oi->mirror, channel, replication); + + r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, + oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, + oi->out_width, oi->out_height, oi->color_mode, oi->rotation, + oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, + oi->rotation_type, replication, mgr_timings, mem_to_mem); + + return r; +} + +int dispc_wb_setup(const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct omap_video_timings *mgr_timings) +{ + int r; + u32 l; + enum omap_plane plane = OMAP_DSS_WB; + const int pos_x = 0, pos_y = 0; + const u8 zorder = 0, global_alpha = 0; + const bool replication = false; + bool truncation; + int in_width = mgr_timings->x_res; + int in_height = mgr_timings->y_res; + enum omap_overlay_caps caps = + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; + + DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " + "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width, + in_height, wi->width, wi->height, wi->color_mode, wi->rotation, + wi->mirror); + + r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, + wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, + wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder, + wi->pre_mult_alpha, global_alpha, wi->rotation_type, + replication, mgr_timings, mem_to_mem); + + switch (wi->color_mode) { + case OMAP_DSS_COLOR_RGB16: + case OMAP_DSS_COLOR_RGB24P: + case OMAP_DSS_COLOR_ARGB16: + case OMAP_DSS_COLOR_RGBA16: + case OMAP_DSS_COLOR_RGB12U: + case OMAP_DSS_COLOR_ARGB16_1555: + case OMAP_DSS_COLOR_XRGB16_1555: + case OMAP_DSS_COLOR_RGBX16: + truncation = true; + break; + default: + truncation = false; + break; + } + + /* setup extra DISPC_WB_ATTRIBUTES */ + l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ + l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ + dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + + return r; +} + int dispc_ovl_enable(enum omap_plane plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); @@ -2451,6 +2728,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable) BUG(); } +void dispc_wb_enable(bool enable) +{ + enum omap_plane plane = OMAP_DSS_WB; + struct completion frame_done_completion; + bool is_on; + int r; + u32 irq; + + is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); + irq = DISPC_IRQ_FRAMEDONEWB; + + if (!enable && is_on) { + init_completion(&frame_done_completion); + + r = omap_dispc_register_isr(dispc_disable_isr, + &frame_done_completion, irq); + if (r) + DSSERR("failed to register FRAMEDONEWB isr\n"); + } + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + + if (!enable && is_on) { + if (!wait_for_completion_timeout(&frame_done_completion, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for FRAMEDONEWB\n"); + + r = omap_dispc_unregister_isr(dispc_disable_isr, + &frame_done_completion, irq); + if (r) + DSSERR("failed to unregister FRAMEDONEWB isr\n"); + } +} + +bool dispc_wb_is_enabled(void) +{ + enum omap_plane plane = OMAP_DSS_WB; + + return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); +} + void dispc_lcd_enable_signal_polarity(bool act_high) { if (!dss_has_feature(FEAT_LCDENABLEPOL)) @@ -2605,24 +2923,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height) static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, int vsw, int vfp, int vbp) { - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { - if (hsw < 1 || hsw > 64 || - hfp < 1 || hfp > 256 || - hbp < 1 || hbp > 256 || - vsw < 1 || vsw > 64 || - vfp < 0 || vfp > 255 || - vbp < 0 || vbp > 255) - return false; - } else { - if (hsw < 1 || hsw > 256 || - hfp < 1 || hfp > 4096 || - hbp < 1 || hbp > 4096 || - vsw < 1 || vsw > 256 || - vfp < 0 || vfp > 4095 || - vbp < 0 || vbp > 4095) - return false; - } - + if (hsw < 1 || hsw > dispc.feat->sw_max || + hfp < 1 || hfp > dispc.feat->hp_max || + hbp < 1 || hbp > dispc.feat->hp_max || + vsw < 1 || vsw > dispc.feat->sw_max || + vfp < 0 || vfp > dispc.feat->vp_max || + vbp < 0 || vbp > dispc.feat->vp_max) + return false; return true; } @@ -2654,19 +2961,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, u32 timing_h, timing_v, l; bool onoff, rf, ipc; - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { - timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | - FLD_VAL(hbp-1, 27, 20); - - timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | - FLD_VAL(vbp, 27, 20); - } else { - timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | - FLD_VAL(hbp-1, 31, 20); - - timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | - FLD_VAL(vbp, 31, 20); - } + timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | + FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | + FLD_VAL(hbp-1, dispc.feat->bp_start, 20); + timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) | + FLD_VAL(vfp, dispc.feat->fp_start, 8) | + FLD_VAL(vbp, dispc.feat->bp_start, 20); dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); @@ -2872,6 +3172,23 @@ unsigned long dispc_core_clk_rate(void) return fclk / lcd; } +static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) +{ + enum omap_channel channel = dispc_ovl_get_channel_out(plane); + + return dispc_mgr_pclk_rate(channel); +} + +static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) +{ + enum omap_channel channel = dispc_ovl_get_channel_out(plane); + + if (dss_mgr_is_lcd(channel)) + return dispc_mgr_lclk_rate(channel); + else + return dispc_fclk_rate(); + +} static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) { int lcd, pcd; @@ -3492,7 +3809,7 @@ static void dispc_error_worker(struct work_struct *work) ovl->name); dispc_ovl_enable(ovl->id, false); dispc_mgr_go(ovl->manager->id); - mdelay(50); + msleep(50); } } @@ -3504,7 +3821,7 @@ static void dispc_error_worker(struct work_struct *work) bit = mgr_desc[i].sync_lost_irq; if (bit & errors) { - struct omap_dss_device *dssdev = mgr->device; + struct omap_dss_device *dssdev = mgr->get_device(mgr); bool enable; DSSERR("SYNC_LOST on channel %s, restarting the output " @@ -3524,7 +3841,7 @@ static void dispc_error_worker(struct work_struct *work) } dispc_mgr_go(mgr->id); - mdelay(50); + msleep(50); if (enable) dssdev->driver->enable(dssdev); @@ -3535,9 +3852,13 @@ static void dispc_error_worker(struct work_struct *work) DSSERR("OCP_ERR\n"); for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { struct omap_overlay_manager *mgr; + struct omap_dss_device *dssdev; + mgr = omap_dss_get_overlay_manager(i); - if (mgr->device && mgr->device->driver) - mgr->device->driver->disable(mgr->device); + dssdev = mgr->get_device(mgr); + + if (dssdev && dssdev->driver) + dssdev->driver->disable(dssdev); } } @@ -3661,17 +3982,98 @@ static void _omap_dispc_initial_config(void) if (dss_has_feature(FEAT_FUNCGATED)) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); - _dispc_setup_color_conv_coef(); + dispc_setup_color_conv_coef(); dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); - dispc_read_plane_fifo_sizes(); + dispc_init_fifos(); dispc_configure_burst_sizes(); dispc_ovl_enable_zorder_planes(); } +static const struct dispc_features omap24xx_dispc_feats __initconst = { + .sw_start = 5, + .fp_start = 15, + .bp_start = 27, + .sw_max = 64, + .vp_max = 255, + .hp_max = 256, + .calc_scaling = dispc_ovl_calc_scaling_24xx, + .calc_core_clk = calc_core_clk_24xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { + .sw_start = 5, + .fp_start = 15, + .bp_start = 27, + .sw_max = 64, + .vp_max = 255, + .hp_max = 256, + .calc_scaling = dispc_ovl_calc_scaling_34xx, + .calc_core_clk = calc_core_clk_34xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .calc_scaling = dispc_ovl_calc_scaling_34xx, + .calc_core_clk = calc_core_clk_34xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap44xx_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .calc_scaling = dispc_ovl_calc_scaling_44xx, + .calc_core_clk = calc_core_clk_44xx, + .num_fifos = 5, + .gfx_fifo_workaround = true, +}; + +static int __init dispc_init_features(struct device *dev) +{ + const struct dispc_features *src; + struct dispc_features *dst; + + dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + if (!dst) { + dev_err(dev, "Failed to allocate DISPC Features\n"); + return -ENOMEM; + } + + if (cpu_is_omap24xx()) { + src = &omap24xx_dispc_feats; + } else if (cpu_is_omap34xx()) { + if (omap_rev() < OMAP3430_REV_ES3_0) + src = &omap34xx_rev1_0_dispc_feats; + else + src = &omap34xx_rev3_0_dispc_feats; + } else if (cpu_is_omap44xx()) { + src = &omap44xx_dispc_feats; + } else if (soc_is_omap54xx()) { + src = &omap44xx_dispc_feats; + } else { + return -ENODEV; + } + + memcpy(dst, src, sizeof(*dst)); + dispc.feat = dst; + + return 0; +} + /* DISPC HW IP initialisation */ static int __init omap_dispchw_probe(struct platform_device *pdev) { @@ -3682,6 +4084,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dispc.pdev = pdev; + r = dispc_init_features(&dispc.pdev->dev); + if (r) + return r; + spin_lock_init(&dispc.irq_lock); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 92d8a9be86fc..222363c6e623 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -36,6 +36,7 @@ #define DISPC_CONTROL2 0x0238 #define DISPC_CONFIG2 0x0620 #define DISPC_DIVISOR 0x0804 +#define DISPC_GLOBAL_BUFFER 0x0800 #define DISPC_CONTROL3 0x0848 #define DISPC_CONFIG3 0x084C @@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) return 0x014C; case OMAP_DSS_VIDEO3: return 0x0300; + case OMAP_DSS_WB: + return 0x0500; default: BUG(); return 0; @@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0000; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0008; default: BUG(); @@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0004; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x000C; default: BUG(); @@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) return 0x04BC; case OMAP_DSS_VIDEO3: return 0x0310; + case OMAP_DSS_WB: + return 0x0118; default: BUG(); return 0; @@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) return 0x04C0; case OMAP_DSS_VIDEO3: return 0x0314; + case OMAP_DSS_WB: + return 0x011C; default: BUG(); return 0; @@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x000C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x00A8; default: BUG(); @@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0010; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0070; default: BUG(); @@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) return 0x04DC; case OMAP_DSS_VIDEO3: return 0x032C; + case OMAP_DSS_WB: + return 0x0310; default: BUG(); return 0; @@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0014; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x008C; default: BUG(); @@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0018; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0088; default: BUG(); @@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x001C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x00A4; default: BUG(); @@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0020; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0098; default: BUG(); @@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0024; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0090; default: BUG(); @@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) return 0x055C; case OMAP_DSS_VIDEO3: return 0x0424; + case OMAP_DSS_WB: + return 0x290; default: BUG(); return 0; @@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0028; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0094; default: BUG(); @@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x002C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0000; default: BUG(); @@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) return 0x0560; case OMAP_DSS_VIDEO3: return 0x0428; + case OMAP_DSS_WB: + return 0x0294; default: BUG(); return 0; @@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0030; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0004; default: BUG(); @@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) return 0x0564; case OMAP_DSS_VIDEO3: return 0x042C; + case OMAP_DSS_WB: + return 0x0298; default: BUG(); return 0; @@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x0034 + i * 0x8; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0010 + i * 0x8; default: BUG(); @@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) return 0x0568 + i * 0x8; case OMAP_DSS_VIDEO3: return 0x0430 + i * 0x8; + case OMAP_DSS_WB: + return 0x02A0 + i * 0x8; default: BUG(); return 0; @@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x0038 + i * 0x8; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0014 + i * 0x8; default: BUG(); @@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) return 0x056C + i * 0x8; case OMAP_DSS_VIDEO3: return 0x0434 + i * 0x8; + case OMAP_DSS_WB: + return 0x02A4 + i * 0x8; default: BUG(); return 0; @@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0074 + i * 0x4; default: BUG(); @@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x00B4 + i * 0x4; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0050 + i * 0x4; default: BUG(); @@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) return 0x05A8 + i * 0x4; case OMAP_DSS_VIDEO3: return 0x0470 + i * 0x4; + case OMAP_DSS_WB: + return 0x02E0 + i * 0x4; default: BUG(); return 0; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 5bd957e85505..ccf8550fafde 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev, if (r) return r; + dssdev->driver->disable(dssdev); dssdev->driver->set_timings(dssdev, &t); + r = dssdev->driver->enable(dssdev); + if (r) + return r; return size; } @@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_default_get_timings); -void dss_init_device(struct platform_device *pdev, +/* + * Connect dssdev to a manager if the manager is free or if force is specified. + * Connect all overlays to that manager if they are free or if force is + * specified. + */ +static int dss_init_connections(struct omap_dss_device *dssdev, bool force) +{ + struct omap_dss_output *out; + struct omap_overlay_manager *mgr; + int i, r; + + out = omapdss_get_output_from_dssdev(dssdev); + + WARN_ON(dssdev->output); + WARN_ON(out->device); + + r = omapdss_output_set_device(out, dssdev); + if (r) { + DSSERR("failed to connect output to new device\n"); + return r; + } + + mgr = omap_dss_get_overlay_manager(dssdev->channel); + + if (mgr->output && !force) + return 0; + + if (mgr->output) + mgr->unset_output(mgr); + + r = mgr->set_output(mgr, out); + if (r) { + DSSERR("failed to connect manager to output of new device\n"); + + /* remove the output-device connection we just made */ + omapdss_output_unset_device(out); + return r; + } + + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl = omap_dss_get_overlay(i); + + if (!ovl->manager || force) { + if (ovl->manager) + ovl->unset_manager(ovl); + + r = ovl->set_manager(ovl, mgr); + if (r) { + DSSERR("failed to set initial overlay\n"); + return r; + } + } + } + + return 0; +} + +static void dss_uninit_connections(struct omap_dss_device *dssdev) +{ + if (dssdev->output) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + + if (mgr) + mgr->unset_output(mgr); + + omapdss_output_unset_device(dssdev->output); + } +} + +int dss_init_device(struct platform_device *pdev, struct omap_dss_device *dssdev) { struct device_attribute *attr; - int i; - int r; + int i, r; + const char *def_disp_name = dss_get_default_display_name(); + bool force; + + force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0; + dss_init_connections(dssdev, force); /* create device sysfs files */ i = 0; while ((attr = display_sysfs_attrs[i++]) != NULL) { r = device_create_file(&dssdev->dev, attr); - if (r) + if (r) { + for (i = i - 2; i >= 0; i--) { + attr = display_sysfs_attrs[i]; + device_remove_file(&dssdev->dev, attr); + } + + dss_uninit_connections(dssdev); + DSSERR("failed to create sysfs file\n"); + return r; + } } /* create display? sysfs links */ r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, dev_name(&dssdev->dev)); - if (r) + if (r) { + while ((attr = display_sysfs_attrs[i++]) != NULL) + device_remove_file(&dssdev->dev, attr); + + dss_uninit_connections(dssdev); + DSSERR("failed to create sysfs display link\n"); + return r; + } + + return 0; } void dss_uninit_device(struct platform_device *pdev, @@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev, while ((attr = display_sysfs_attrs[i++]) != NULL) device_remove_file(&dssdev->dev, attr); - if (dssdev->manager) - dssdev->manager->unset_device(dssdev->manager); + dss_uninit_connections(dssdev); } static int dss_suspend_device(struct device *dev, void *data) diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 3266be23fc0d..56748cf8760e 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -29,17 +29,24 @@ #include <linux/errno.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/string.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" +#include "dss_features.h" static struct { struct regulator *vdds_dsi_reg; struct platform_device *dsidev; + struct mutex lock; + + struct omap_video_timings timings; struct dss_lcd_mgr_config mgr_config; + int data_lines; + + struct omap_dss_output output; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) @@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, static int dpi_set_mode(struct omap_dss_device *dssdev) { - struct omap_video_timings *t = &dssdev->panel.timings; + struct omap_video_timings *t = &dpi.timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div = 0, pck_div = 0; unsigned long fck = 0; unsigned long pck; @@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dss_mgr_set_timings(dssdev->manager, t); + dss_mgr_set_timings(mgr, t); return 0; } static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi.mgr_config.stallmode = false; dpi.mgr_config.fifohandcheck = false; - dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines; + dpi.mgr_config.video_port_width = dpi.data_lines; dpi.mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config); + dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); } int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_output *out = dssdev->output; int r; - if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) { + mutex_lock(&dpi.lock); + + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { DSSERR("no VDSS_DSI regulator\n"); - return -ENODEV; + r = -ENODEV; + goto err_no_reg; } - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); - return -ENODEV; + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err_no_out_mgr; } r = omap_dss_start_device(dssdev); @@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err_start_dev; } - if (cpu_is_omap34xx()) { + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) goto err_reg_enable; @@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; + r = dss_dpi_select_source(dssdev->channel); + if (r) + goto err_src_sel; + if (dpi_use_dsi_pll(dssdev)) { r = dsi_runtime_get(dpi.dsidev); if (r) @@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(out->manager); if (r) goto err_mgr_enable; + mutex_unlock(&dpi.lock); + return 0; err_mgr_enable: @@ -227,20 +248,28 @@ err_dsi_pll_init: if (dpi_use_dsi_pll(dssdev)) dsi_runtime_put(dpi.dsidev); err_get_dsi: +err_src_sel: dispc_runtime_put(); err_get_dispc: - if (cpu_is_omap34xx()) + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); err_reg_enable: omap_dss_stop_device(dssdev); err_start_dev: +err_no_out_mgr: +err_no_reg: + mutex_unlock(&dpi.lock); return r; } EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + mutex_lock(&dpi.lock); + + dss_mgr_disable(mgr); if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); @@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) dispc_runtime_put(); - if (cpu_is_omap34xx()) + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); omap_dss_stop_device(dssdev); + + mutex_unlock(&dpi.lock); } EXPORT_SYMBOL(omapdss_dpi_display_disable); -void dpi_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { - int r; - DSSDBG("dpi_set_timings\n"); - dssdev->panel.timings = *timings; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = dispc_runtime_get(); - if (r) - return; - dpi_set_mode(dssdev); + mutex_lock(&dpi.lock); - dispc_runtime_put(); - } else { - dss_mgr_set_timings(dssdev->manager, timings); - } + dpi.timings = *timings; + + mutex_unlock(&dpi.lock); } -EXPORT_SYMBOL(dpi_set_timings); +EXPORT_SYMBOL(omapdss_dpi_set_timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { int r; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div, pck_div; unsigned long fck; unsigned long pck; struct dispc_clock_info dispc_cinfo; - if (dss_mgr_check_timings(dssdev->manager, timings)) + if (dss_mgr_check_timings(mgr, timings)) return -EINVAL; if (timings->pixel_clock == 0) @@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(dpi_check_timings); +void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) +{ + mutex_lock(&dpi.lock); + + dpi.data_lines = data_lines; + + mutex_unlock(&dpi.lock); +} +EXPORT_SYMBOL(omapdss_dpi_set_data_lines); + static int __init dpi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) { + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && + dpi.vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; vdds_dsi = dss_get_vdds_dsi(); @@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __init dpi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) continue; - r = dpi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init dpi_probe_pdata(struct platform_device *dpidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = dpi_find_dssdev(dpidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&dpidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = dpi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } } +static void __init dpi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &dpi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_DPI; + out->type = OMAP_DISPLAY_TYPE_DPI; + + dss_register_output(out); +} + +static void __exit dpi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &dpi.output; + + dss_unregister_output(out); +} + static int __init omap_dpi_probe(struct platform_device *pdev) { + mutex_init(&dpi.lock); + + dpi_init_output(pdev); + dpi_probe_pdata(pdev); return 0; @@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev) static int __exit omap_dpi_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + dpi_uninit_output(pdev); return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 05ee04667af1..d64ac3842884 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -41,7 +41,6 @@ #include <video/omapdss.h> #include <video/mipi_display.h> -#include <plat/clock.h> #include "dss.h" #include "dss_features.h" @@ -333,6 +332,12 @@ struct dsi_data { unsigned scp_clk_refcount; struct dss_lcd_mgr_config mgr_config; + struct omap_video_timings timings; + enum omap_dss_dsi_pixel_format pix_fmt; + enum omap_dss_dsi_mode mode; + struct omap_dss_dsi_videomode_timings vm_timings; + + struct omap_dss_output output; }; struct dsi_packet_sent_handler_data { @@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data { struct completion *completion; }; -static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; - #ifdef DEBUG static bool dsi_perf; module_param(dsi_perf, bool, 0644); @@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) { - return dsi_pdev_map[dssdev->phy.dsi.module]; + return dssdev->output->pdev; } struct platform_device *dsi_get_dsidev_from_id(int module) { - return dsi_pdev_map[module]; + struct omap_dss_output *out; + enum omap_dss_output_id id; + + id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + + out = omap_dss_get_output(id); + + return out->pdev; } static inline void dsi_write_reg(struct platform_device *dsidev, @@ -1450,6 +1460,148 @@ found: return 0; } +static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, + unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cur, best; + + DSSDBG("dsi_pll_calc_ddrfreq\n"); + + memset(&best, 0, sizeof(best)); + memset(&cur, 0, sizeof(cur)); + + cur.clkin = clk_get_rate(dsi->sys_clk); + + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { + cur.fint = cur.clkin / cur.regn; + + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) + continue; + + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { + unsigned long a, b; + + a = 2 * cur.regm * (cur.clkin/1000); + b = cur.regn; + cur.clkin4ddr = a / b * 1000; + + if (cur.clkin4ddr > 1800 * 1000 * 1000) + break; + + if (abs(cur.clkin4ddr - req_clkin4ddr) < + abs(best.clkin4ddr - req_clkin4ddr)) { + best = cur; + DSSDBG("best %ld\n", best.clkin4ddr); + } + + if (cur.clkin4ddr == req_clkin4ddr) + goto found; + } + } +found: + if (cinfo) + *cinfo = best; + + return 0; +} + +static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, + struct dsi_clock_info *cinfo) +{ + unsigned long max_dsi_fck; + + max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); + + cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck); + cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; +} + +static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, + unsigned long req_pck, struct dsi_clock_info *cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned regm_dispc, best_regm_dispc; + unsigned long dispc_clk, best_dispc_clk; + int min_fck_per_pck; + unsigned long max_dss_fck; + struct dispc_clock_info best_dispc; + bool match; + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; + + if (min_fck_per_pck && + req_pck * min_fck_per_pck > max_dss_fck) { + DSSERR("Requested pixel clock not possible with the current " + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " + "the constraint off.\n"); + min_fck_per_pck = 0; + } + +retry: + best_regm_dispc = 0; + best_dispc_clk = 0; + memset(&best_dispc, 0, sizeof(best_dispc)); + match = false; + + for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { + struct dispc_clock_info cur_dispc; + + dispc_clk = cinfo->clkin4ddr / regm_dispc; + + /* this will narrow down the search a bit, + * but still give pixclocks below what was + * requested */ + if (dispc_clk < req_pck) + break; + + if (dispc_clk > max_dss_fck) + continue; + + if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) + continue; + + match = true; + + dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); + + if (abs(cur_dispc.pck - req_pck) < + abs(best_dispc.pck - req_pck)) { + best_regm_dispc = regm_dispc; + best_dispc_clk = dispc_clk; + best_dispc = cur_dispc; + + if (cur_dispc.pck == req_pck) + goto found; + } + } + + if (!match) { + if (min_fck_per_pck) { + DSSERR("Could not find suitable clock settings.\n" + "Turning FCK/PCK constraint off and" + "trying again.\n"); + min_fck_per_pck = 0; + goto retry; + } + + DSSERR("Could not find suitable clock settings.\n"); + + return -EINVAL; + } +found: + cinfo->regm_dispc = best_regm_dispc; + cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; + + *dispc_cinfo = best_dispc; + + return 0; +} + int dsi_pll_set_clock_div(struct platform_device *dsidev, struct dsi_clock_info *cinfo) { @@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); + l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); + if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { f = cinfo->fint < 1000000 ? 0x3 : cinfo->fint < 1250000 ? 0x4 : cinfo->fint < 1500000 ? 0x5 : cinfo->fint < 1750000 ? 0x6 : 0x7; - } - l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); - - if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ + } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { + f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; + + l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */ + } + l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ + if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) + l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ @@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) return 1194 * 3; /* 1194x24 bits */ case 6: return 1365 * 3; /* 1365x24 bits */ + case 7: + return 1920 * 3; /* 1920x24 bits */ default: BUG(); return 0; } } -static int dsi_set_lane_config(struct omap_dss_device *dssdev) +static int dsi_set_lane_config(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); static const u8 offsets[] = { 0, 4, 8, 12, 16 }; static const enum dsi_lane_function functions[] = { @@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); - r = FLD_MOD(r, tlpx_half, 22, 16); + r = FLD_MOD(r, tlpx_half, 20, 16); r = FLD_MOD(r, tclk_trail, 15, 8); r = FLD_MOD(r, tclk_zero, 7, 0); + + if (dss_has_feature(FEAT_DSI_PHY_DCC)) { + r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ + r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ + r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ + } + dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); @@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev) } /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ -static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, +static void dsi_cio_enable_lane_override(struct platform_device *dsidev, unsigned mask_p, unsigned mask_n) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u32 l; @@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); } -static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) +static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t, i; bool in_use[DSI_MAX_NR_LANES]; @@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) } /* return bitmask of enabled lanes, lane0 being the lsb */ -static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) +static unsigned dsi_get_lane_mask(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned mask = 0; int i; @@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) return mask; } -static int dsi_cio_init(struct omap_dss_device *dssdev) +static int dsi_cio_init(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; u32 l; DSSDBGF(); - r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); if (r) return r; @@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) goto err_scp_clk_dom; } - r = dsi_set_lane_config(dssdev); + r = dsi_set_lane_config(dsidev); if (r) goto err_scp_clk_dom; @@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) mask_p |= 1 << i; } - dsi_cio_enable_lane_override(dssdev, mask_p, 0); + dsi_cio_enable_lane_override(dsidev, mask_p, 0); } r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); @@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_if_enable(dsidev, false); REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ - r = dsi_cio_wait_tx_clk_esc_reset(dssdev); + r = dsi_cio_wait_tx_clk_esc_reset(dsidev); if (r) goto err_tx_clk_esc_rst; @@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_cio_timings(dsidev); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* DDR_CLK_ALWAYS_ON */ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, - dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13); + dsi->vm_timings.ddr_clk_always_on, 13, 13); } dsi->ulps_enabled = false; @@ -2381,13 +2543,12 @@ err_cio_pwr: dsi_cio_disable_lane_override(dsidev); err_scp_clk_dom: dsi_disable_scp_clk(dsidev); - dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); return r; } -static void dsi_cio_uninit(struct omap_dss_device *dssdev) +static void dsi_cio_uninit(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); /* DDR_CLK_ALWAYS_ON */ @@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev) dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); dsi_disable_scp_clk(dsidev); - dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); } static void dsi_config_tx_fifo(struct platform_device *dsidev, @@ -2685,6 +2846,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); @@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, dsi_force_tx_stop_mode_io(dsidev); /* start the DDR clock by sending a NULL packet */ - if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable) + if (dsi->vm_timings.ddr_clk_always_on && enable) dsi_vc_send_null(dssdev, channel); } EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); @@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) } EXPORT_SYMBOL(dsi_vc_send_null); -static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, +static int dsi_vc_write_nosync_common(struct platform_device *dsidev, int channel, u8 *data, int len, enum dss_dsi_content_type type) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; if (len == 0) { @@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - return dsi_vc_write_nosync_common(dssdev, channel, data, len, + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + + return dsi_vc_write_nosync_common(dsidev, channel, data, len, DSS_DSI_CONTENT_DCS); } EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); @@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - return dsi_vc_write_nosync_common(dssdev, channel, data, len, + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + + return dsi_vc_write_nosync_common(dsidev, channel, data, len, DSS_DSI_CONTENT_GENERIC); } EXPORT_SYMBOL(dsi_vc_generic_write_nosync); @@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type); + r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); if (r) goto err; @@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel, } EXPORT_SYMBOL(dsi_vc_generic_write_2); -static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, +static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, int channel, u8 dcs_cmd) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; @@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, return 0; } -static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, +static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, int channel, u8 *reqdata, int reqlen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 data; u8 data_type; @@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd); + r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); if (r) goto err; @@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen); + r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); if (r) return r; @@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) +static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int num_line_buffers; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + int bpp = dsi_get_pixel_size(dsi->pix_fmt); unsigned line_buf_size = dsi_get_line_buf_size(dsidev); - struct omap_video_timings *timings = &dssdev->panel.timings; + struct omap_video_timings *timings = &dsi->timings; /* * Don't use line buffers if width is greater than the video * port's line buffer size @@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); } -static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) +static void dsi_config_vp_sync_events(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end; - bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + bool vsync_end = dsi->vm_timings.vp_vsync_end; + bool hsync_end = dsi->vm_timings.vp_hsync_end; u32 r; r = dsi_read_reg(dsidev, DSI_CTRL); @@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); } -static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) +static void dsi_config_blanking_modes(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode; - int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode; - int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode; - int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int blanking_mode = dsi->vm_timings.blanking_mode; + int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; + int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; + int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode; u32 r; /* @@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; int tclk_trail, ths_exit, exiths_clk; bool ddr_alwon; - struct omap_video_timings *timings = &dssdev->panel.timings; - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + struct omap_video_timings *timings = &dsi->timings; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); int ndl = dsi->num_lanes_used - 1; int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; int hsa_interleave_hs = 0, hsa_interleave_lp = 0; @@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) static int dsi_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; @@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); - switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) { + switch (dsi_get_pixel_size(dsi->pix_fmt)) { case 16: buswidth = 0; break; @@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); - dsi_config_vp_num_line_buffers(dssdev); + dsi_config_vp_num_line_buffers(dsidev); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_config_vp_sync_events(dssdev); - dsi_config_blanking_modes(dssdev); + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_config_vp_sync_events(dsidev); + dsi_config_blanking_modes(dsidev); dsi_config_cmd_mode_interleaving(dssdev); } @@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) return 0; } -static void dsi_proto_timings(struct omap_dss_device *dssdev) +static void dsi_proto_timings(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; unsigned tclk_pre, tclk_post; @@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) ths_exit = FLD_GET(r, 7, 0); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); - tlpx = FLD_GET(r, 22, 16) * 2; + tlpx = FLD_GET(r, 20, 16) * 2; tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); @@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", enter_hs_mode_lat, exit_hs_mode_lat); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* TODO: Implement a video mode check_timings function */ - int hsa = dssdev->panel.dsi_vm_data.hsa; - int hfp = dssdev->panel.dsi_vm_data.hfp; - int hbp = dssdev->panel.dsi_vm_data.hbp; - int vsa = dssdev->panel.dsi_vm_data.vsa; - int vfp = dssdev->panel.dsi_vm_data.vfp; - int vbp = dssdev->panel.dsi_vm_data.vbp; - int window_sync = dssdev->panel.dsi_vm_data.window_sync; - bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; - struct omap_video_timings *timings = &dssdev->panel.timings; - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + int hsa = dsi->vm_timings.hsa; + int hfp = dsi->vm_timings.hfp; + int hbp = dsi->vm_timings.hbp; + int vsa = dsi->vm_timings.vsa; + int vfp = dsi->vm_timings.vfp; + int vbp = dsi->vm_timings.vbp; + int window_sync = dsi->vm_timings.window_sync; + bool hsync_end = dsi->vm_timings.vp_hsync_end; + struct omap_video_timings *timings = &dsi->timings; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); int tl, t_he, width_bytes; t_he = hsync_end ? @@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_dsi_configure_pins); -int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cinfo; + struct dispc_clock_info dispc_cinfo; + unsigned lp_clk_div; + unsigned long dsi_fclk; int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + unsigned long pck; + int r; + + DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); + + mutex_lock(&dsi->lock); + + /* Calculate PLL output clock */ + r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); + if (r) + goto err; + + /* Calculate PLL's DSI clock */ + dsi_pll_calc_dsi_fck(dsidev, &cinfo); + + /* Calculate PLL's DISPC clock and pck & lck divs */ + pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; + DSSDBG("finding dispc dividers for pck %lu\n", pck); + r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); + if (r) + goto err; + + /* Calculate LP clock */ + dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; + lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); + + dssdev->clocks.dsi.regn = cinfo.regn; + dssdev->clocks.dsi.regm = cinfo.regm; + dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; + dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; + + dssdev->clocks.dsi.lp_clk_div = lp_clk_div; + + dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; + dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; + + dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; + + dssdev->clocks.dispc.channel.lcd_clk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; + + dssdev->clocks.dsi.dsi_fclk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; + + mutex_unlock(&dsi->lock); + return 0; +err: + mutex_unlock(&dsi->lock); + return r; +} +EXPORT_SYMBOL(omapdss_dsi_set_clocks); + +int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); u8 data_type; u16 word_count; int r; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - switch (dssdev->panel.dsi_pix_fmt) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + switch (dsi->pix_fmt) { case OMAP_DSS_DSI_FMT_RGB888: data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; break; @@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) /* MODE, 1 = video mode */ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); - word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); + word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8); dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); @@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) { - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); dsi_vc_enable(dsidev, channel, false); } @@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output); void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); dsi_vc_enable(dsidev, channel, false); @@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - dss_mgr_disable(dssdev->manager); + dss_mgr_disable(mgr); } EXPORT_SYMBOL(dsi_disable_video_output); -static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, - u16 w, u16 h) +static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned bytespp; unsigned bytespl; unsigned bytespf; @@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, int r; const unsigned channel = dsi->update_channel; const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); + u16 w = dsi->timings.x_res; + u16 h = dsi->timings.y_res; DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); - bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; bytespl = w * bytespp; bytespf = bytespl * h; @@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_mgr_start_update(dssdev->manager); + dss_mgr_set_timings(mgr, &dsi->timings); + + dss_mgr_start_update(mgr); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) static void dsi_framedone_irq_callback(void *data, u32 mask) { - struct omap_dss_device *dssdev = (struct omap_dss_device *) data; - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct platform_device *dsidev = (struct platform_device *) data; struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); /* Note: We get FRAMEDONE when DISPC has finished sending pixels and @@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel, dsi->framedone_callback = callback; dsi->framedone_data = data; - dssdev->driver->get_resolution(dssdev, &dw, &dh); + dw = dsi->timings.x_res; + dh = dsi->timings.y_res; #ifdef DEBUG dsi->update_bytes = dw * dh * - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + dsi_get_pixel_size(dsi->pix_fmt) / 8; #endif - dsi_update_screen_dispc(dssdev, dw, dh); + dsi_update_screen_dispc(dssdev); return 0; } @@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_video_timings timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; u32 irq = 0; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { - u16 dw, dh; - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - timings.x_res = dw; - timings.y_res = dh; - timings.hsw = 1; - timings.hfp = 1; - timings.hbp = 1; - timings.vsw = 1; - timings.vfp = 0; - timings.vbp = 0; + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { + dsi->timings.hsw = 1; + dsi->timings.hfp = 1; + dsi->timings.hbp = 1; + dsi->timings.vsw = 1; + dsi->timings.vfp = 0; + dsi->timings.vbp = 0; - irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); + irq = dispc_mgr_get_framedone_irq(mgr->id); r = omap_dispc_register_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); if (r) { DSSERR("can't get FRAMEDONE irq\n"); goto err; @@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->mgr_config.stallmode = true; dsi->mgr_config.fifohandcheck = true; } else { - timings = dssdev->panel.timings; - dsi->mgr_config.stallmode = false; dsi->mgr_config.fifohandcheck = false; } @@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) * override interlace, logic level and edge related parameters in * omap_video_timings with default values */ - timings.interlace = false; - timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + dsi->timings.interlace = false; + dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; - dss_mgr_set_timings(dssdev->manager, &timings); + dss_mgr_set_timings(mgr, &dsi->timings); r = dsi_configure_dispc_clocks(dssdev); if (r) @@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dsi->mgr_config.video_port_width = - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + dsi_get_pixel_size(dsi->pix_fmt); dsi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config); + dss_mgr_set_lcd_config(mgr, &dsi->mgr_config); return 0; err1: - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); err: return r; } static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) { - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { u32 irq; - irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); + irq = dispc_mgr_get_framedone_irq(mgr->id); omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); } } @@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; r = dsi_pll_init(dsidev, true, true); @@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); - dss_select_lcd_clk_source(dssdev->manager->id, + dss_select_lcd_clk_source(mgr->id, dssdev->clocks.dispc.channel.lcd_clk_src); DSSDBG("PLL OK\n"); - r = dsi_cio_init(dssdev); + r = dsi_cio_init(dsidev); if (r) goto err2; _dsi_print_reset_status(dsidev); - dsi_proto_timings(dssdev); + dsi_proto_timings(dsidev); dsi_set_lp_clk_divisor(dssdev); if (1) @@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) return 0; err3: - dsi_cio_uninit(dssdev); + dsi_cio_uninit(dsidev); err2: dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); - dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); err1: dsi_pll_uninit(dsidev, true); @@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; if (enter_ulps && !dsi->ulps_enabled) dsi_enter_ulps(dsidev); @@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); - dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); - dsi_cio_uninit(dssdev); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + dsi_cio_uninit(dsidev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -4559,6 +4794,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("dsi_display_enable\n"); @@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dsi->lock); - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err_start_dev; } @@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) } EXPORT_SYMBOL(omapdss_dsi_enable_te); -static int __init dsi_init_display(struct omap_dss_device *dssdev) +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - DSSDBG("DSI init\n"); + mutex_lock(&dsi->lock); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | - OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; - } + dsi->timings = *timings; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_timings); + +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->timings.x_res = w; + dsi->timings.y_res = h; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_size); + +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->pix_fmt = fmt; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); + +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->mode = mode; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); + +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->vm_timings = *timings; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); + +static int __init dsi_init_display(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = + dsi_get_dsidev_from_id(dssdev->phy.dsi.module); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + DSSDBG("DSI init\n"); if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev) clk_put(dsi->sys_clk); } -static void __init dsi_probe_pdata(struct platform_device *dsidev) +static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_board_info *pdata = dsidev->dev.platform_data; - int i, r; + struct omap_dss_board_info *pdata = pdev->dev.platform_data; + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) if (dssdev->phy.dsi.module != dsi->module_id) continue; - r = dsi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &dsidev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init dsi_probe_pdata(struct platform_device *dsidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = dsi_find_dssdev(dsidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&dsidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = dsi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } } +static void __init dsi_init_output(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = &dsi->output; + + out->pdev = dsidev; + out->id = dsi->module_id == 0 ? + OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + + out->type = OMAP_DISPLAY_TYPE_DSI; + + dss_register_output(out); +} + +static void __exit dsi_uninit_output(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = &dsi->output; + + dss_unregister_output(out); +} + /* DSI1 HW IP initialisation */ static int __init omap_dsihw_probe(struct platform_device *dsidev) { @@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) dsi->module_id = dsidev->id; dsi->pdev = dsidev; - dsi_pdev_map[dsi->module_id] = dsidev; dev_set_drvdata(&dsidev->dev, dsi); spin_lock_init(&dsi->irq_lock); @@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) else dsi->num_lanes_supported = 3; + dsi_init_output(dsidev); + dsi_probe_pdata(dsidev); dsi_runtime_put(dsidev); @@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) WARN_ON(dsi->scp_clk_refcount > 0); - omap_dss_unregister_child_devices(&dsidev->dev); + dss_unregister_child_devices(&dsidev->dev); + + dsi_uninit_output(dsidev); pm_runtime_disable(&dsidev->dev); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 04b4586113e3..2ab1c3e96553 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -31,11 +31,11 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/gfp.h> #include <video/omapdss.h> #include <plat/cpu.h> -#include <plat/clock.h> #include "dss.h" #include "dss_features.h" @@ -65,6 +65,13 @@ struct dss_reg { static int dss_runtime_get(void); static void dss_runtime_put(void); +struct dss_features { + u8 fck_div_max; + u8 dss_fck_multiplier; + const char *clk_name; + int (*dpi_select_source)(enum omap_channel channel); +}; + static struct { struct platform_device *pdev; void __iomem *base; @@ -83,6 +90,8 @@ static struct { bool ctx_valid; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; + + const struct dss_features *feat; } dss; static const char * const dss_generic_clk_source_names[] = { @@ -144,7 +153,7 @@ static void dss_restore_context(void) #undef SR #undef RR -void dss_sdi_init(u8 datapairs) +void dss_sdi_init(int datapairs) { u32 l; @@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) return dss_generic_clk_source_names[clk_src]; } - void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; @@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - if (cpu_is_omap3630() || cpu_is_omap44xx()) - seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); - else - seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); + seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n", + fclk_name, fclk_real_name, dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss.feat->dss_fck_multiplier, fclk_rate); } else { seq_printf(s, "%s (%s) = %lu\n", fclk_name, fclk_real_name, @@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) } } -/* calculate clock rates using dividers in cinfo */ -int dss_calc_clock_rates(struct dss_clock_info *cinfo) -{ - if (dss.dpll4_m4_ck) { - unsigned long prate; - u16 fck_div_max = 16; - - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; - - if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) - return -EINVAL; - - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - - cinfo->fck = prate / cinfo->fck_div; - } else { - if (cinfo->fck_div != 0) - return -EINVAL; - cinfo->fck = clk_get_rate(dss.dss_clk); - } - - return 0; -} - int dss_set_clock_div(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { @@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) return 0; } -int dss_get_clock_div(struct dss_clock_info *cinfo) -{ - cinfo->fck = clk_get_rate(dss.dss_clk); - - if (dss.dpll4_m4_ck) { - unsigned long prate; - - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - - if (cpu_is_omap3630() || cpu_is_omap44xx()) - cinfo->fck_div = prate / (cinfo->fck); - else - cinfo->fck_div = prate / (cinfo->fck / 2); - } else { - cinfo->fck_div = 0; - } - - return 0; -} - unsigned long dss_get_dpll4_rate(void) { if (dss.dpll4_m4_ck) @@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, unsigned long fck, max_dss_fck; - u16 fck_div, fck_div_max = 16; + u16 fck_div; int match = 0; int min_fck_per_pck; @@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); fck = clk_get_rate(dss.dss_clk); - if (req_pck == dss.cache_req_pck && - ((cpu_is_omap34xx() && prate == dss.cache_prate) || - dss.cache_dss_cinfo.fck == fck)) { + if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && + dss.cache_dss_cinfo.fck == fck) { DSSDBG("dispc clock info found from cache.\n"); *dss_cinfo = dss.cache_dss_cinfo; *dispc_cinfo = dss.cache_dispc_cinfo; @@ -564,16 +518,10 @@ retry: goto found; } else { - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; - - for (fck_div = fck_div_max; fck_div > 0; --fck_div) { + for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { struct dispc_clock_info cur_dispc; - if (fck_div_max == 32) - fck = prate / fck_div; - else - fck = prate / fck_div * 2; + fck = prate / fck_div * dss.feat->dss_fck_multiplier; if (fck > max_dss_fck) continue; @@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) +void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) { - REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ + enum omap_display_type dp; + dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); + + /* Complain about invalid selections */ + WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC)); + WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI)); + + /* Select only if we have options */ + if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI)) + REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ } enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) @@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) return DSS_VENC_TV_CLK; + if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0) + return DSS_HDMI_M_PCLK; + return REG_GET(DSS_CONTROL, 15, 15); } +static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) +{ + if (channel != OMAP_DSS_CHANNEL_LCD) + return -EINVAL; + + return 0; +} + +static int dss_dpi_select_source_omap4(enum omap_channel channel) +{ + int val; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD2: + val = 0; + break; + case OMAP_DSS_CHANNEL_DIGIT: + val = 1; + break; + default: + return -EINVAL; + } + + REG_FLD_MOD(DSS_CONTROL, val, 17, 17); + + return 0; +} + +static int dss_dpi_select_source_omap5(enum omap_channel channel) +{ + int val; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + val = 1; + break; + case OMAP_DSS_CHANNEL_LCD2: + val = 2; + break; + case OMAP_DSS_CHANNEL_LCD3: + val = 3; + break; + case OMAP_DSS_CHANNEL_DIGIT: + val = 0; + break; + default: + return -EINVAL; + } + + REG_FLD_MOD(DSS_CONTROL, val, 17, 16); + + return 0; +} + +int dss_dpi_select_source(enum omap_channel channel) +{ + return dss.feat->dpi_select_source(channel); +} + static int dss_get_clocks(void) { struct clk *clk; @@ -678,22 +697,11 @@ static int dss_get_clocks(void) dss.dss_clk = clk; - if (cpu_is_omap34xx()) { - clk = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(clk); - goto err; - } - } else if (cpu_is_omap44xx()) { - clk = clk_get(NULL, "dpll_per_m5x2_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll_per_m5x2_ck\n"); - r = PTR_ERR(clk); - goto err; - } - } else { /* omap24xx */ - clk = NULL; + clk = clk_get(NULL, dss.feat->clk_name); + if (IS_ERR(clk)) { + DSSERR("Failed to get %s\n", dss.feat->clk_name); + r = PTR_ERR(clk); + goto err; } dss.dpll4_m4_ck = clk; @@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s) } #endif +static const struct dss_features omap24xx_dss_feats __initconst = { + .fck_div_max = 16, + .dss_fck_multiplier = 2, + .clk_name = NULL, + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap34xx_dss_feats __initconst = { + .fck_div_max = 16, + .dss_fck_multiplier = 2, + .clk_name = "dpll4_m4_ck", + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap3630_dss_feats __initconst = { + .fck_div_max = 32, + .dss_fck_multiplier = 1, + .clk_name = "dpll4_m4_ck", + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap44xx_dss_feats __initconst = { + .fck_div_max = 32, + .dss_fck_multiplier = 1, + .clk_name = "dpll_per_m5x2_ck", + .dpi_select_source = &dss_dpi_select_source_omap4, +}; + +static const struct dss_features omap54xx_dss_feats __initconst = { + .fck_div_max = 64, + .dss_fck_multiplier = 1, + .clk_name = "dpll_per_h12x2_ck", + .dpi_select_source = &dss_dpi_select_source_omap5, +}; + +static int __init dss_init_features(struct device *dev) +{ + const struct dss_features *src; + struct dss_features *dst; + + dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + if (!dst) { + dev_err(dev, "Failed to allocate local DSS Features\n"); + return -ENOMEM; + } + + if (cpu_is_omap24xx()) + src = &omap24xx_dss_feats; + else if (cpu_is_omap34xx()) + src = &omap34xx_dss_feats; + else if (cpu_is_omap3630()) + src = &omap3630_dss_feats; + else if (cpu_is_omap44xx()) + src = &omap44xx_dss_feats; + else if (soc_is_omap54xx()) + src = &omap54xx_dss_feats; + else + return -ENODEV; + + memcpy(dst, src, sizeof(*dst)); + dss.feat = dst; + + return 0; +} + /* DSS HW IP initialisation */ static int __init omap_dsshw_probe(struct platform_device *pdev) { @@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.pdev = pdev; + r = dss_init_features(&dss.pdev->dev); + if (r) + return r; + dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); if (!dss_mem) { DSSERR("can't get IORESOURCE_MEM DSS\n"); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index f67afe76f217..6728892f9dad 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -113,6 +113,17 @@ enum dss_dsi_content_type { DSS_DSI_CONTENT_GENERIC, }; +enum dss_writeback_channel { + DSS_WB_LCD1_MGR = 0, + DSS_WB_LCD2_MGR = 1, + DSS_WB_TV_MGR = 2, + DSS_WB_OVL0 = 3, + DSS_WB_OVL1 = 4, + DSS_WB_OVL2 = 5, + DSS_WB_OVL3 = 6, + DSS_WB_LCD3_MGR = 7, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -175,6 +186,7 @@ struct seq_file; struct platform_device; /* core */ +const char *dss_get_default_display_name(void); struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); @@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); int dss_set_min_bus_tput(struct device *dev, unsigned long tput); int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); -int omap_dss_register_device(struct omap_dss_device *dssdev, - struct device *parent, int disp_num); -void omap_dss_unregister_device(struct omap_dss_device *dssdev); -void omap_dss_unregister_child_devices(struct device *parent); +struct omap_dss_device *dss_alloc_and_init_device(struct device *parent); +int dss_add_device(struct omap_dss_device *dssdev); +void dss_unregister_device(struct omap_dss_device *dssdev); +void dss_unregister_child_devices(struct device *parent); +void dss_put_device(struct omap_dss_device *dssdev); +void dss_copy_device_pdata(struct omap_dss_device *dst, + const struct omap_dss_device *src); /* apply */ void dss_apply_init(void); @@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, int dss_mgr_set_device(struct omap_overlay_manager *mgr, struct omap_dss_device *dssdev); int dss_mgr_unset_device(struct omap_overlay_manager *mgr); +int dss_mgr_set_output(struct omap_overlay_manager *mgr, + struct omap_dss_output *output); +int dss_mgr_unset_output(struct omap_overlay_manager *mgr); void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings); + const struct omap_video_timings *timings); void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, const struct dss_lcd_mgr_config *config); const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); @@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, struct omap_overlay_manager *mgr); int dss_ovl_unset_manager(struct omap_overlay *ovl); +/* output */ +void dss_register_output(struct omap_dss_output *out); +void dss_unregister_output(struct omap_dss_output *out); +struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev); + /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); void dss_disable_all_devices(void); -void dss_init_device(struct platform_device *pdev, +int dss_init_device(struct platform_device *pdev, struct omap_dss_device *dssdev); void dss_uninit_device(struct platform_device *pdev, struct omap_dss_device *dssdev); @@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) return false; } +int dss_manager_kobj_init(struct omap_overlay_manager *mgr, + struct platform_device *pdev); +void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr); + /* overlay */ void dss_init_overlays(struct platform_device *pdev); void dss_uninit_overlays(struct platform_device *pdev); void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); -void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); int dss_ovl_simple_check(struct omap_overlay *ovl, const struct omap_overlay_info *info); int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, const struct omap_video_timings *mgr_timings); bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, enum omap_color_mode mode); +int dss_overlay_kobj_init(struct omap_overlay *ovl, + struct platform_device *pdev); +void dss_overlay_kobj_uninit(struct omap_overlay *ovl); /* DSS */ int dss_init_platform_driver(void) __init; void dss_uninit_platform_driver(void); +int dss_dpi_select_source(enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); @@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s); void dss_debug_dump_clocks(struct seq_file *s); #endif -void dss_sdi_init(u8 datapairs); +void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); @@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); unsigned long dss_get_dpll4_rate(void); -int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo); -int dss_get_clock_div(struct dss_clock_info *cinfo); int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo); @@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, bool manual_update); -int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings); +int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem); int dispc_ovl_enable(enum omap_plane plane, bool enable); void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel); @@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, void dispc_mgr_setup(enum omap_channel channel, struct omap_overlay_manager_info *info); +u32 dispc_wb_get_framedone_irq(void); +bool dispc_wb_go_busy(void); +void dispc_wb_go(void); +void dispc_wb_enable(bool enable); +bool dispc_wb_is_enabled(void); +void dispc_wb_set_channel_in(enum dss_writeback_channel channel); +int dispc_wb_setup(const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct omap_video_timings *timings); + /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC int venc_init_platform_driver(void) __init; @@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void) return 0; } #endif +int omapdss_venc_display_enable(struct omap_dss_device *dssdev); +void omapdss_venc_display_disable(struct omap_dss_device *dssdev); +void omapdss_venc_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +int omapdss_venc_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev); +int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss); +void omapdss_venc_set_type(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type); +void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, + bool invert_polarity); +int venc_panel_init(void); +void venc_panel_exit(void); /* HDMI */ #ifdef CONFIG_OMAP4_DSS_HDMI @@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void) #endif int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); -void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings); int omapdss_hdmi_read_edid(u8 *buf, int len); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 938709724f0c..acbc1e1efba3 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -46,7 +46,9 @@ struct omap_dss_features { const int num_mgrs; const int num_ovls; + const int num_wbs; const enum omap_display_type *supported_displays; + const enum omap_dss_output_id *supported_outputs; const enum omap_color_mode *supported_color_modes; const enum omap_overlay_caps *overlay_caps; const char * const *clksrc_names; @@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, }; +static const struct dss_reg_field omap5_dss_reg_fields[] = { + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, + [FEAT_REG_FIFOSIZE] = { 15, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, + [FEAT_REG_VERTICALACCU] = { 26, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, + [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, + [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, + [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, + [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, +}; + static const enum omap_display_type omap2_dss_supported_displays[] = { /* OMAP_DSS_CHANNEL_LCD */ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, @@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_DSI, }; +static const enum omap_display_type omap5_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, +}; + +static const enum omap_dss_output_id omap2_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | + OMAP_DSS_OUTPUT_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI2, +}; + +static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_LCD3 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI2, +}; + static const enum omap_color_mode omap2_dss_supported_color_modes[] = { /* OMAP_DSS_GFX */ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | @@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | OMAP_DSS_COLOR_RGBX32, + + /* OMAP_DSS_WB */ + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | + OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | + OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | + OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | + OMAP_DSS_COLOR_RGBX32, }; static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - 0, + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ - OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | - OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO3 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; static const char * const omap2_dss_clk_source_names[] = { @@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = { [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", }; +static const char * const omap5_dss_clk_source_names[] = { + [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1", + [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2", + [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2", +}; + static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, [FEAT_PARAM_DSS_PCD] = { 2, 255 }, @@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, + [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, @@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, + [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, + [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, + [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, +}; + +static const struct dss_param_range omap5_dss_param_range[] = { + [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, + [FEAT_PARAM_DSS_PCD] = { 1, 255 }, + [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, + [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, + [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, @@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = { FEAT_ALPHA_FIXED_ZORDER, FEAT_FIFO_MERGE, FEAT_OMAP3_DSI_FIFO_BUG, + FEAT_DPI_USES_VDDS_DSI, +}; + +static const enum dss_feat_id am35xx_dss_feat_list[] = { + FEAT_LCDENABLEPOL, + FEAT_LCDENABLESIGNAL, + FEAT_PCKFREEENABLE, + FEAT_FUNCGATED, + FEAT_LINEBUFFERSPLIT, + FEAT_ROWREPEATENABLE, + FEAT_RESIZECONF, + FEAT_DSI_PLL_FREQSEL, + FEAT_DSI_REVERSE_TXCLKESC, + FEAT_VENC_REQUIRES_TV_DAC_CLK, + FEAT_CPR, + FEAT_PRELOAD, + FEAT_FIR_COEF_V, + FEAT_ALPHA_FIXED_ZORDER, + FEAT_FIFO_MERGE, + FEAT_OMAP3_DSI_FIFO_BUG, }; static const enum dss_feat_id omap3630_dss_feat_list[] = { @@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = { FEAT_BURST_2D, }; +static const enum dss_feat_id omap5_dss_feat_list[] = { + FEAT_MGR_LCD2, + FEAT_CORE_CLK_DIV, + FEAT_LCD_CLK_SRC, + FEAT_DSI_DCS_CMD_CONFIG_VC, + FEAT_DSI_VC_OCP_WIDTH, + FEAT_DSI_GNQ, + FEAT_HDMI_CTS_SWMODE, + FEAT_HDMI_AUDIO_USE_MCLK, + FEAT_HANDLE_UV_SEPARATE, + FEAT_ATTR2, + FEAT_CPR, + FEAT_PRELOAD, + FEAT_FIR_COEF_V, + FEAT_ALPHA_FREE_ZORDER, + FEAT_FIFO_MERGE, + FEAT_BURST_2D, + FEAT_DSI_PLL_SELFREQDCO, + FEAT_DSI_PLL_REFSEL, + FEAT_DSI_PHY_DCC, +}; + /* OMAP2 DSS Features */ static const struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, @@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, + .supported_outputs = omap2_dss_supported_outputs, .supported_color_modes = omap2_dss_supported_color_modes, .overlay_caps = omap2_dss_overlay_caps, .clksrc_names = omap2_dss_clk_source_names, @@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3430_dss_supported_displays, + .supported_outputs = omap3430_dss_supported_outputs, + .supported_color_modes = omap3_dss_supported_color_modes, + .overlay_caps = omap3430_dss_overlay_caps, + .clksrc_names = omap3_dss_clk_source_names, + .dss_params = omap3_dss_param_range, + .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, + .buffer_size_unit = 1, + .burst_size_unit = 8, +}; + +/* + * AM35xx DSS Features. This is basically OMAP3 DSS Features without the + * vdds_dsi regulator. + */ +static const struct omap_dss_features am35xx_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .features = am35xx_dss_feat_list, + .num_features = ARRAY_SIZE(am35xx_dss_feat_list), + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3430_dss_supported_displays, + .supported_outputs = omap3430_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3430_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, @@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3630_dss_supported_displays, + .supported_outputs = omap3630_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3630_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, @@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = { .burst_size_unit = 16, }; +/* OMAP5 DSS Features */ +static const struct omap_dss_features omap5_dss_features = { + .reg_fields = omap5_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields), + + .features = omap5_dss_feat_list, + .num_features = ARRAY_SIZE(omap5_dss_feat_list), + + .num_mgrs = 3, + .num_ovls = 4, + .supported_displays = omap5_dss_supported_displays, + .supported_outputs = omap5_dss_supported_outputs, + .supported_color_modes = omap4_dss_supported_color_modes, + .overlay_caps = omap4_dss_overlay_caps, + .clksrc_names = omap5_dss_clk_source_names, + .dss_params = omap5_dss_param_range, + .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, + .buffer_size_unit = 16, + .burst_size_unit = 16, +}; + #if defined(CONFIG_OMAP4_DSS_HDMI) /* HDMI OMAP4 Functions*/ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { @@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void) return omap_current_dss_features->num_ovls; } +int dss_feat_get_num_wbs(void) +{ + return omap_current_dss_features->num_wbs; +} + unsigned long dss_feat_get_param_min(enum dss_range_param param) { return omap_current_dss_features->dss_params[param].min; @@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel return omap_current_dss_features->supported_displays[channel]; } +enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) +{ + return omap_current_dss_features->supported_outputs[channel]; +} + enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) { return omap_current_dss_features->supported_color_modes[plane]; @@ -694,8 +935,13 @@ void dss_features_init(void) omap_current_dss_features = &omap2_dss_features; else if (cpu_is_omap3630()) omap_current_dss_features = &omap3630_dss_features; - else if (cpu_is_omap34xx()) - omap_current_dss_features = &omap3430_dss_features; + else if (cpu_is_omap34xx()) { + if (soc_is_am35xx()) { + omap_current_dss_features = &am35xx_dss_features; + } else { + omap_current_dss_features = &omap3430_dss_features; + } + } else if (omap_rev() == OMAP4430_REV_ES1_0) omap_current_dss_features = &omap4430_es1_0_dss_features; else if (omap_rev() == OMAP4430_REV_ES2_0 || @@ -704,6 +950,8 @@ void dss_features_init(void) omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; else if (cpu_is_omap44xx()) omap_current_dss_features = &omap4_dss_features; + else if (soc_is_omap54xx()) + omap_current_dss_features = &omap5_dss_features; else DSSWARN("Unsupported OMAP version"); } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 996ffcbfed58..9218113b5e88 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -50,6 +50,7 @@ enum dss_feat_id { FEAT_DSI_VC_OCP_WIDTH, FEAT_DSI_REVERSE_TXCLKESC, FEAT_DSI_GNQ, + FEAT_DPI_USES_VDDS_DSI, FEAT_HDMI_CTS_SWMODE, FEAT_HDMI_AUDIO_USE_MCLK, FEAT_HANDLE_UV_SEPARATE, @@ -64,6 +65,9 @@ enum dss_feat_id { /* An unknown HW bug causing the normal FIFO thresholds not to work */ FEAT_OMAP3_DSI_FIFO_BUG, FEAT_BURST_2D, + FEAT_DSI_PLL_SELFREQDCO, + FEAT_DSI_PLL_REFSEL, + FEAT_DSI_PHY_DCC, }; /* DSS register field id */ @@ -91,6 +95,7 @@ enum dss_range_param { FEAT_PARAM_DSIPLL_REGM_DSI, FEAT_PARAM_DSIPLL_FINT, FEAT_PARAM_DSIPLL_LPDIV, + FEAT_PARAM_DSI_FCK, FEAT_PARAM_DOWNSCALE, FEAT_PARAM_LINEWIDTH, FEAT_PARAM_MGR_WIDTH, @@ -100,9 +105,11 @@ enum dss_range_param { /* DSS Feature Functions */ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); +int dss_feat_get_num_wbs(void); unsigned long dss_feat_get_param_min(enum dss_range_param param); unsigned long dss_feat_get_param_max(enum dss_range_param param); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); +enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 060216fdc578..a48a7dd75b33 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -32,6 +32,8 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> #include <video/omapdss.h> #include "ti_hdmi.h" @@ -61,6 +63,13 @@ static struct { struct hdmi_ip_data ip_data; struct clk *sys_clk; + struct regulator *vdda_hdmi_dac_reg; + + int ct_cp_hpd_gpio; + int ls_oe_gpio; + int hpd_gpio; + + struct omap_dss_output output; } hdmi; /* @@ -314,12 +323,47 @@ static void hdmi_runtime_put(void) static int __init hdmi_init_display(struct omap_dss_device *dssdev) { + int r; + + struct gpio gpios[] = { + { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" }, + { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" }, + { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" }, + }; + DSSDBG("init_display\n"); dss_init_hdmi_ip_ops(&hdmi.ip_data); + + if (hdmi.vdda_hdmi_dac_reg == NULL) { + struct regulator *reg; + + reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); + + if (IS_ERR(reg)) { + DSSERR("can't get VDDA_HDMI_DAC regulator\n"); + return PTR_ERR(reg); + } + + hdmi.vdda_hdmi_dac_reg = reg; + } + + r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (r) + return r; + return 0; } +static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) +{ + DSSDBG("uninit_display\n"); + + gpio_free(hdmi.ct_cp_hpd_gpio); + gpio_free(hdmi.ls_oe_gpio); + gpio_free(hdmi.hpd_gpio); +} + static const struct hdmi_config *hdmi_find_timing( const struct hdmi_config *timings_arr, int len) @@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, static int hdmi_power_on(struct omap_dss_device *dssdev) { int r; - const struct hdmi_config *timing; struct omap_video_timings *p; + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned long phy; + gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); + gpio_set_value(hdmi.ls_oe_gpio, 1); + + /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ + udelay(300); + + r = regulator_enable(hdmi.vdda_hdmi_dac_reg); + if (r) + goto err_vdac_enable; + r = hdmi_runtime_get(); if (r) - return r; + goto err_runtime_get; - dss_mgr_disable(dssdev->manager); + dss_mgr_disable(mgr); - p = &dssdev->panel.timings; + p = &hdmi.ip_data.cfg.timings; - DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", - dssdev->panel.timings.x_res, - dssdev->panel.timings.y_res); + DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); - timing = hdmi_get_timings(); - if (timing == NULL) { - /* HDMI code 4 corresponds to 640 * 480 VGA */ - hdmi.ip_data.cfg.cm.code = 4; - /* DVI mode 1 corresponds to HDMI 0 to DVI */ - hdmi.ip_data.cfg.cm.mode = HDMI_DVI; - hdmi.ip_data.cfg = vesa_timings[0]; - } else { - hdmi.ip_data.cfg = *timing; - } phy = p->pixel_clock; hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); @@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to lock PLL\n"); - goto err; + goto err_pll_enable; } r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to start PHY\n"); - goto err; + goto err_phy_enable; } hdmi.ip_data.ops->video_configure(&hdmi.ip_data); @@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dispc_enable_gamma_table(0); /* tv size */ - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); + dss_mgr_set_timings(mgr, p); r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); if (r) goto err_vid_enable; - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) goto err_mgr_enable; @@ -537,20 +579,33 @@ err_mgr_enable: hdmi.ip_data.ops->video_disable(&hdmi.ip_data); err_vid_enable: hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); +err_phy_enable: hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); -err: +err_pll_enable: hdmi_runtime_put(); +err_runtime_get: + regulator_disable(hdmi.vdda_hdmi_dac_reg); +err_vdac_enable: + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); return -EIO; } static void hdmi_power_off(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + dss_mgr_disable(mgr); hdmi.ip_data.ops->video_disable(&hdmi.ip_data); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); hdmi_runtime_put(); + + regulator_disable(hdmi.vdda_hdmi_dac_reg); + + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); } int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, @@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, } -void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { struct hdmi_cm cm; + const struct hdmi_config *t; - cm = hdmi_get_code(&dssdev->panel.timings); - hdmi.ip_data.cfg.cm.code = cm.code; - hdmi.ip_data.cfg.cm.mode = cm.mode; + mutex_lock(&hdmi.lock); - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - int r; + cm = hdmi_get_code(timings); + hdmi.ip_data.cfg.cm = cm; - hdmi_power_off(dssdev); + t = hdmi_get_timings(); + if (t != NULL) + hdmi.ip_data.cfg = *t; - r = hdmi_power_on(dssdev); - if (r) - DSSERR("failed to power on device\n"); - } else { - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); - } + mutex_unlock(&hdmi.lock); } static void hdmi_dump_regs(struct seq_file *s) @@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void) int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_hdmi_data *priv = dssdev->data; + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi.lock); - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - hdmi.ip_data.hpd_gpio = priv->hpd_gpio; + hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; r = omap_dss_start_device(dssdev); if (r) { @@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) { - DSSERR("failed to enable GPIO's\n"); - goto err1; - } - } - r = hdmi_power_on(dssdev); if (r) { DSSERR("failed to power on device\n"); - goto err2; + goto err1; } mutex_unlock(&hdmi.lock); return 0; -err2: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); err1: omap_dss_stop_device(dssdev); err0: @@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) hdmi_power_off(dssdev); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - omap_dss_stop_device(dssdev); mutex_unlock(&hdmi.lock); @@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio) #endif -static void __init hdmi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int r, i; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) continue; - r = hdmi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init hdmi_probe_pdata(struct platform_device *pdev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + struct omap_dss_hdmi_data *priv; + int r; + + plat_dssdev = hdmi_find_dssdev(pdev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&pdev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + priv = dssdev->data; + + hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio; + hdmi.ls_oe_gpio = priv->ls_oe_gpio; + hdmi.hpd_gpio = priv->hpd_gpio; + + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + + r = hdmi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init hdmi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &hdmi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; + + dss_register_output(out); +} + +static void __exit hdmi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &hdmi.output; + + dss_unregister_output(out); } /* HDMI HW IP initialisation */ @@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.core_av_offset = HDMI_CORE_AV; hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; + mutex_init(&hdmi.ip_data.lock); hdmi_panel_init(); dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi_init_output(pdev); + hdmi_probe_pdata(pdev); return 0; } +static int __exit hdmi_remove_child(struct device *dev, void *data) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + hdmi_uninit_display(dssdev); + return 0; +} + static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + device_for_each_child(&pdev->dev, NULL, hdmi_remove_child); + + dss_unregister_child_devices(&pdev->dev); hdmi_panel_exit(); + hdmi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); hdmi_put_clocks(); diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index e10844faadf9..69fb115bab32 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c @@ -41,17 +41,34 @@ static struct { static int hdmi_panel_probe(struct omap_dss_device *dssdev) { + /* Initialize default timings to VGA in DVI mode */ + const struct omap_video_timings default_timings = { + .x_res = 640, + .y_res = 480, + .pixel_clock = 25175, + .hsw = 96, + .hfp = 16, + .hbp = 48, + .vsw = 2, + .vfp = 11, + .vbp = 31, + + .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, + .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, + + .interlace = false, + }; + DSSDBG("ENTER hdmi_panel_probe\n"); - dssdev->panel.timings = (struct omap_video_timings) - { 640, 480, 25175, 96, 16, 48, 2, 11, 31, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, - }; + dssdev->panel.timings = default_timings; DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); + + omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); + return 0; } @@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) goto err; } + omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); + r = omapdss_hdmi_display_enable(dssdev); if (r) { DSSERR("failed to power on\n"); @@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, */ hdmi_panel_audio_disable(dssdev); + omapdss_hdmi_display_set_timing(dssdev, timings); dssdev->panel.timings = *timings; - omapdss_hdmi_display_set_timing(dssdev); mutex_unlock(&hdmi.lock); } diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c new file mode 100644 index 000000000000..9a2fb59b6f89 --- /dev/null +++ b/drivers/video/omap2/dss/manager-sysfs.c @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "MANAGER" + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/jiffies.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); +} + +static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) +{ + struct omap_dss_device *dssdev = mgr->get_device(mgr); + + return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? + dssdev->name : "<none>"); +} + +static ssize_t manager_display_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + int r = 0; + size_t len = size; + struct omap_dss_device *dssdev = NULL; + + int match(struct omap_dss_device *dssdev, void *data) + { + const char *str = data; + return sysfs_streq(dssdev->name, str); + } + + if (buf[size-1] == '\n') + --len; + + if (len > 0) + dssdev = omap_dss_find_device((void *)buf, match); + + if (len > 0 && dssdev == NULL) + return -EINVAL; + + if (dssdev) + DSSDBG("display %s found\n", dssdev->name); + + if (mgr->output) { + r = mgr->unset_output(mgr); + if (r) { + DSSERR("failed to unset current output\n"); + goto put_device; + } + } + + if (dssdev) { + struct omap_dss_output *out = dssdev->output; + + /* + * a registered device should have an output connected to it + * already + */ + if (!out) { + DSSERR("device has no output connected to it\n"); + goto put_device; + } + + r = mgr->set_output(mgr, out); + if (r) { + DSSERR("failed to set manager output\n"); + goto put_device; + } + + r = mgr->apply(mgr); + if (r) { + DSSERR("failed to apply dispc config\n"); + goto put_device; + } + } + +put_device: + if (dssdev) + omap_dss_put_device(dssdev); + + return r ? r : size; +} + +static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); +} + +static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + u32 color; + int r; + + r = kstrtouint(buf, 0, &color); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.default_color = color; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static const char *trans_key_type_str[] = { + "gfx-destination", + "video-source", +}; + +static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, + char *buf) +{ + enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + key_type = info.trans_key_type; + BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); + + return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); +} + +static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + int r; + + for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; + key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { + if (sysfs_streq(buf, trans_key_type_str[key_type])) + break; + } + + if (key_type == ARRAY_SIZE(trans_key_type_str)) + return -EINVAL; + + mgr->get_manager_info(mgr, &info); + + info.trans_key_type = key_type; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); +} + +static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + u32 key_value; + int r; + + r = kstrtouint(buf, 0, &key_value); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.trans_key = key_value; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); +} + +static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + bool enable; + int r; + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.trans_enabled = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_alpha_blending_enabled_show( + struct omap_overlay_manager *mgr, char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.partial_alpha_enabled); +} + +static ssize_t manager_alpha_blending_enabled_store( + struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + bool enable; + int r; + + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.partial_alpha_enabled = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); +} + +static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + int r; + bool enable; + + if (!dss_has_feature(FEAT_CPR)) + return -ENODEV; + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + if (info.cpr_enable == enable) + return size; + + info.cpr_enable = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, + "%d %d %d %d %d %d %d %d %d\n", + info.cpr_coefs.rr, + info.cpr_coefs.rg, + info.cpr_coefs.rb, + info.cpr_coefs.gr, + info.cpr_coefs.gg, + info.cpr_coefs.gb, + info.cpr_coefs.br, + info.cpr_coefs.bg, + info.cpr_coefs.bb); +} + +static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + struct omap_dss_cpr_coefs coefs; + int r, i; + s16 *arr; + + if (!dss_has_feature(FEAT_CPR)) + return -ENODEV; + + if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", + &coefs.rr, &coefs.rg, &coefs.rb, + &coefs.gr, &coefs.gg, &coefs.gb, + &coefs.br, &coefs.bg, &coefs.bb) != 9) + return -EINVAL; + + arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, + coefs.gr, coefs.gg, coefs.gb, + coefs.br, coefs.bg, coefs.bb }; + + for (i = 0; i < 9; ++i) { + if (arr[i] < -512 || arr[i] > 511) + return -EINVAL; + } + + mgr->get_manager_info(mgr, &info); + + info.cpr_coefs = coefs; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +struct manager_attribute { + struct attribute attr; + ssize_t (*show)(struct omap_overlay_manager *, char *); + ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); +}; + +#define MANAGER_ATTR(_name, _mode, _show, _store) \ + struct manager_attribute manager_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); +static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, + manager_display_show, manager_display_store); +static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, + manager_default_color_show, manager_default_color_store); +static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, + manager_trans_key_type_show, manager_trans_key_type_store); +static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, + manager_trans_key_value_show, manager_trans_key_value_store); +static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, + manager_trans_key_enabled_show, + manager_trans_key_enabled_store); +static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, + manager_alpha_blending_enabled_show, + manager_alpha_blending_enabled_store); +static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, + manager_cpr_enable_show, + manager_cpr_enable_store); +static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, + manager_cpr_coef_show, + manager_cpr_coef_store); + + +static struct attribute *manager_sysfs_attrs[] = { + &manager_attr_name.attr, + &manager_attr_display.attr, + &manager_attr_default_color.attr, + &manager_attr_trans_key_type.attr, + &manager_attr_trans_key_value.attr, + &manager_attr_trans_key_enabled.attr, + &manager_attr_alpha_blending_enabled.attr, + &manager_attr_cpr_enable.attr, + &manager_attr_cpr_coef.attr, + NULL +}; + +static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct omap_overlay_manager *manager; + struct manager_attribute *manager_attr; + + manager = container_of(kobj, struct omap_overlay_manager, kobj); + manager_attr = container_of(attr, struct manager_attribute, attr); + + if (!manager_attr->show) + return -ENOENT; + + return manager_attr->show(manager, buf); +} + +static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + struct omap_overlay_manager *manager; + struct manager_attribute *manager_attr; + + manager = container_of(kobj, struct omap_overlay_manager, kobj); + manager_attr = container_of(attr, struct manager_attribute, attr); + + if (!manager_attr->store) + return -ENOENT; + + return manager_attr->store(manager, buf, size); +} + +static const struct sysfs_ops manager_sysfs_ops = { + .show = manager_attr_show, + .store = manager_attr_store, +}; + +static struct kobj_type manager_ktype = { + .sysfs_ops = &manager_sysfs_ops, + .default_attrs = manager_sysfs_attrs, +}; + +int dss_manager_kobj_init(struct omap_overlay_manager *mgr, + struct platform_device *pdev) +{ + return kobject_init_and_add(&mgr->kobj, &manager_ktype, + &pdev->dev.kobj, "manager%d", mgr->id); +} + +void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) +{ + kobject_del(&mgr->kobj); + kobject_put(&mgr->kobj); +} diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 53710fadc82d..c54d2f620ce3 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -36,463 +36,15 @@ static int num_managers; static struct omap_overlay_manager *managers; -static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) +static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) { - return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); + return mgr->output ? mgr->output->device : NULL; } -static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - mgr->device ? mgr->device->name : "<none>"); -} - -static ssize_t manager_display_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - int r = 0; - size_t len = size; - struct omap_dss_device *dssdev = NULL; - - int match(struct omap_dss_device *dssdev, void *data) - { - const char *str = data; - return sysfs_streq(dssdev->name, str); - } - - if (buf[size-1] == '\n') - --len; - - if (len > 0) - dssdev = omap_dss_find_device((void *)buf, match); - - if (len > 0 && dssdev == NULL) - return -EINVAL; - - if (dssdev) - DSSDBG("display %s found\n", dssdev->name); - - if (mgr->device) { - r = mgr->unset_device(mgr); - if (r) { - DSSERR("failed to unset display\n"); - goto put_device; - } - } - - if (dssdev) { - r = mgr->set_device(mgr, dssdev); - if (r) { - DSSERR("failed to set manager\n"); - goto put_device; - } - - r = mgr->apply(mgr); - if (r) { - DSSERR("failed to apply dispc config\n"); - goto put_device; - } - } - -put_device: - if (dssdev) - omap_dss_put_device(dssdev); - - return r ? r : size; -} - -static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); -} - -static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 color; - int r; - - r = kstrtouint(buf, 0, &color); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.default_color = color; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static const char *trans_key_type_str[] = { - "gfx-destination", - "video-source", -}; - -static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, - char *buf) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - key_type = info.trans_key_type; - BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); - - return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); -} - -static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - int r; - - for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; - key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { - if (sysfs_streq(buf, trans_key_type_str[key_type])) - break; - } - - if (key_type == ARRAY_SIZE(trans_key_type_str)) - return -EINVAL; - - mgr->get_manager_info(mgr, &info); - - info.trans_key_type = key_type; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); -} - -static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 key_value; - int r; - - r = kstrtouint(buf, 0, &key_value); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_key = key_value; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); -} - -static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_alpha_blending_enabled_show( - struct omap_overlay_manager *mgr, char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.partial_alpha_enabled); -} - -static ssize_t manager_alpha_blending_enabled_store( - struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.partial_alpha_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); -} - -static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - int r; - bool enable; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - if (info.cpr_enable == enable) - return size; - - info.cpr_enable = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, - "%d %d %d %d %d %d %d %d %d\n", - info.cpr_coefs.rr, - info.cpr_coefs.rg, - info.cpr_coefs.rb, - info.cpr_coefs.gr, - info.cpr_coefs.gg, - info.cpr_coefs.gb, - info.cpr_coefs.br, - info.cpr_coefs.bg, - info.cpr_coefs.bb); -} - -static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - struct omap_dss_cpr_coefs coefs; - int r, i; - s16 *arr; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", - &coefs.rr, &coefs.rg, &coefs.rb, - &coefs.gr, &coefs.gg, &coefs.gb, - &coefs.br, &coefs.bg, &coefs.bb) != 9) - return -EINVAL; - - arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, - coefs.gr, coefs.gg, coefs.gb, - coefs.br, coefs.bg, coefs.bb }; - - for (i = 0; i < 9; ++i) { - if (arr[i] < -512 || arr[i] > 511) - return -EINVAL; - } - - mgr->get_manager_info(mgr, &info); - - info.cpr_coefs = coefs; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -struct manager_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay_manager *, char *); - ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); -}; - -#define MANAGER_ATTR(_name, _mode, _show, _store) \ - struct manager_attribute manager_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); -static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, - manager_display_show, manager_display_store); -static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, - manager_default_color_show, manager_default_color_store); -static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, - manager_trans_key_type_show, manager_trans_key_type_store); -static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, - manager_trans_key_value_show, manager_trans_key_value_store); -static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, - manager_trans_key_enabled_show, - manager_trans_key_enabled_store); -static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, - manager_alpha_blending_enabled_show, - manager_alpha_blending_enabled_store); -static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, - manager_cpr_enable_show, - manager_cpr_enable_store); -static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, - manager_cpr_coef_show, - manager_cpr_coef_store); - - -static struct attribute *manager_sysfs_attrs[] = { - &manager_attr_name.attr, - &manager_attr_display.attr, - &manager_attr_default_color.attr, - &manager_attr_trans_key_type.attr, - &manager_attr_trans_key_value.attr, - &manager_attr_trans_key_enabled.attr, - &manager_attr_alpha_blending_enabled.attr, - &manager_attr_cpr_enable.attr, - &manager_attr_cpr_coef.attr, - NULL -}; - -static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->show) - return -ENOENT; - - return manager_attr->show(manager, buf); -} - -static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->store) - return -ENOENT; - - return manager_attr->store(manager, buf, size); -} - -static const struct sysfs_ops manager_sysfs_ops = { - .show = manager_attr_show, - .store = manager_attr_store, -}; - -static struct kobj_type manager_ktype = { - .sysfs_ops = &manager_sysfs_ops, - .default_attrs = manager_sysfs_attrs, -}; - static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); + struct omap_dss_device *dssdev = mgr->get_device(mgr); u32 irq; int r; @@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) if (r) return r; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) irq = DISPC_IRQ_EVSYNC_ODD; - else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) + else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) irq = DISPC_IRQ_EVSYNC_EVEN; else irq = dispc_mgr_get_vsync_irq(mgr->id); @@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev) break; } - mgr->set_device = &dss_mgr_set_device; - mgr->unset_device = &dss_mgr_unset_device; + mgr->set_output = &dss_mgr_set_output; + mgr->unset_output = &dss_mgr_unset_output; mgr->apply = &omap_dss_mgr_apply; mgr->set_manager_info = &dss_mgr_set_info; mgr->get_manager_info = &dss_mgr_get_info; mgr->wait_for_go = &dss_mgr_wait_for_go; mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; + mgr->get_device = &dss_mgr_get_device; mgr->caps = 0; mgr->supported_displays = dss_feat_get_supported_displays(mgr->id); + mgr->supported_outputs = + dss_feat_get_supported_outputs(mgr->id); INIT_LIST_HEAD(&mgr->overlays); - r = kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "manager%d", i); - + r = dss_manager_kobj_init(mgr, pdev); if (r) DSSERR("failed to create sysfs file\n"); } @@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev) for (i = 0; i < num_managers; ++i) { struct omap_overlay_manager *mgr = &managers[i]; - - kobject_del(&mgr->kobj); - kobject_put(&mgr->kobj); + dss_manager_kobj_uninit(mgr); } kfree(managers); diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c new file mode 100644 index 000000000000..813f26682b7a --- /dev/null +++ b/drivers/video/omap2/dss/output.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012 Texas Instruments Ltd + * Author: Archit Taneja <archit@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <video/omapdss.h> + +#include "dss.h" + +static LIST_HEAD(output_list); +static DEFINE_MUTEX(output_lock); + +int omapdss_output_set_device(struct omap_dss_output *out, + struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&output_lock); + + if (out->device) { + DSSERR("output already has device %s connected to it\n", + out->device->name); + r = -EINVAL; + goto err; + } + + if (out->type != dssdev->type) { + DSSERR("output type and display type don't match\n"); + r = -EINVAL; + goto err; + } + + out->device = dssdev; + dssdev->output = out; + + mutex_unlock(&output_lock); + + return 0; +err: + mutex_unlock(&output_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_output_set_device); + +int omapdss_output_unset_device(struct omap_dss_output *out) +{ + int r; + + mutex_lock(&output_lock); + + if (!out->device) { + DSSERR("output doesn't have a device connected to it\n"); + r = -EINVAL; + goto err; + } + + if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) { + DSSERR("device %s is not disabled, cannot unset device\n", + out->device->name); + r = -EINVAL; + goto err; + } + + out->device->output = NULL; + out->device = NULL; + + mutex_unlock(&output_lock); + + return 0; +err: + mutex_unlock(&output_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_output_unset_device); + +void dss_register_output(struct omap_dss_output *out) +{ + list_add_tail(&out->list, &output_list); +} + +void dss_unregister_output(struct omap_dss_output *out) +{ + list_del(&out->list); +} + +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) +{ + struct omap_dss_output *out; + + list_for_each_entry(out, &output_list, list) { + if (out->id == id) + return out; + } + + return NULL; +} + +struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev) +{ + struct omap_dss_output *out = NULL; + enum omap_dss_output_id id; + + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_DPI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI); + break; + case OMAP_DISPLAY_TYPE_DBI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI); + break; + case OMAP_DISPLAY_TYPE_SDI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI); + break; + case OMAP_DISPLAY_TYPE_VENC: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC); + break; + case OMAP_DISPLAY_TYPE_HDMI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI); + break; + case OMAP_DISPLAY_TYPE_DSI: + id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 : + OMAP_DSS_OUTPUT_DSI2; + out = omap_dss_get_output(id); + break; + default: + break; + } + + return out; +} diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c new file mode 100644 index 000000000000..4cc5ddebfb34 --- /dev/null +++ b/drivers/video/omap2/dss/overlay-sysfs.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "OVERLAY" + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> +#include <linux/platform_device.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); +} + +static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", + ovl->manager ? ovl->manager->name : "<none>"); +} + +static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, + size_t size) +{ + int i, r; + struct omap_overlay_manager *mgr = NULL; + struct omap_overlay_manager *old_mgr; + int len = size; + + if (buf[size-1] == '\n') + --len; + + if (len > 0) { + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + mgr = omap_dss_get_overlay_manager(i); + + if (sysfs_streq(buf, mgr->name)) + break; + + mgr = NULL; + } + } + + if (len > 0 && mgr == NULL) + return -EINVAL; + + if (mgr) + DSSDBG("manager %s found\n", mgr->name); + + if (mgr == ovl->manager) + return size; + + old_mgr = ovl->manager; + + r = dispc_runtime_get(); + if (r) + return r; + + /* detach old manager */ + if (old_mgr) { + r = ovl->unset_manager(ovl); + if (r) { + DSSERR("detach failed\n"); + goto err; + } + + r = old_mgr->apply(old_mgr); + if (r) + goto err; + } + + if (mgr) { + r = ovl->set_manager(ovl, mgr); + if (r) { + DSSERR("Failed to attach overlay\n"); + goto err; + } + + r = mgr->apply(mgr); + if (r) + goto err; + } + + dispc_runtime_put(); + + return size; + +err: + dispc_runtime_put(); + return r; +} + +static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.width, info.height); +} + +static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); +} + +static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.pos_x, info.pos_y); +} + +static ssize_t overlay_position_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + char *last; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.pos_x = simple_strtoul(buf, &last, 10); + ++last; + if (last - buf >= size) + return -EINVAL; + + info.pos_y = simple_strtoul(last, &last, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.out_width, info.out_height); +} + +static ssize_t overlay_output_size_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + char *last; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.out_width = simple_strtoul(buf, &last, 10); + ++last; + if (last - buf >= size) + return -EINVAL; + + info.out_height = simple_strtoul(last, &last, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); +} + +static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, + size_t size) +{ + int r; + bool enable; + + r = strtobool(buf, &enable); + if (r) + return r; + + if (enable) + r = ovl->enable(ovl); + else + r = ovl->disable(ovl); + + if (r) + return r; + + return size; +} + +static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.global_alpha); +} + +static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 alpha; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &alpha); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.global_alpha = alpha; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, + char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.pre_mult_alpha); +} + +static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 alpha; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &alpha); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.pre_mult_alpha = alpha; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); +} + +static ssize_t overlay_zorder_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 zorder; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &zorder); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.zorder = zorder; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +struct overlay_attribute { + struct attribute attr; + ssize_t (*show)(struct omap_overlay *, char *); + ssize_t (*store)(struct omap_overlay *, const char *, size_t); +}; + +#define OVERLAY_ATTR(_name, _mode, _show, _store) \ + struct overlay_attribute overlay_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); +static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, + overlay_manager_show, overlay_manager_store); +static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); +static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); +static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, + overlay_position_show, overlay_position_store); +static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, + overlay_output_size_show, overlay_output_size_store); +static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, + overlay_enabled_show, overlay_enabled_store); +static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, + overlay_global_alpha_show, overlay_global_alpha_store); +static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, + overlay_pre_mult_alpha_show, + overlay_pre_mult_alpha_store); +static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, + overlay_zorder_show, overlay_zorder_store); + +static struct attribute *overlay_sysfs_attrs[] = { + &overlay_attr_name.attr, + &overlay_attr_manager.attr, + &overlay_attr_input_size.attr, + &overlay_attr_screen_width.attr, + &overlay_attr_position.attr, + &overlay_attr_output_size.attr, + &overlay_attr_enabled.attr, + &overlay_attr_global_alpha.attr, + &overlay_attr_pre_mult_alpha.attr, + &overlay_attr_zorder.attr, + NULL +}; + +static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct omap_overlay *overlay; + struct overlay_attribute *overlay_attr; + + overlay = container_of(kobj, struct omap_overlay, kobj); + overlay_attr = container_of(attr, struct overlay_attribute, attr); + + if (!overlay_attr->show) + return -ENOENT; + + return overlay_attr->show(overlay, buf); +} + +static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + struct omap_overlay *overlay; + struct overlay_attribute *overlay_attr; + + overlay = container_of(kobj, struct omap_overlay, kobj); + overlay_attr = container_of(attr, struct overlay_attribute, attr); + + if (!overlay_attr->store) + return -ENOENT; + + return overlay_attr->store(overlay, buf, size); +} + +static const struct sysfs_ops overlay_sysfs_ops = { + .show = overlay_attr_show, + .store = overlay_attr_store, +}; + +static struct kobj_type overlay_ktype = { + .sysfs_ops = &overlay_sysfs_ops, + .default_attrs = overlay_sysfs_attrs, +}; + +int dss_overlay_kobj_init(struct omap_overlay *ovl, + struct platform_device *pdev) +{ + return kobject_init_and_add(&ovl->kobj, &overlay_ktype, + &pdev->dev.kobj, "overlay%d", ovl->id); +} + +void dss_overlay_kobj_uninit(struct omap_overlay *ovl) +{ + kobject_del(&ovl->kobj); + kobject_put(&ovl->kobj); +} diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 952c6fad9a81..45f4994bc6b0 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -26,13 +26,11 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/kobject.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/slab.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -40,417 +38,13 @@ static int num_overlays; static struct omap_overlay *overlays; -static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) +static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) { - return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); + return ovl->manager ? + (ovl->manager->output ? ovl->manager->output->device : NULL) : + NULL; } -static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - ovl->manager ? ovl->manager->name : "<none>"); -} - -static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int i, r; - struct omap_overlay_manager *mgr = NULL; - struct omap_overlay_manager *old_mgr; - int len = size; - - if (buf[size-1] == '\n') - --len; - - if (len > 0) { - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - mgr = omap_dss_get_overlay_manager(i); - - if (sysfs_streq(buf, mgr->name)) - break; - - mgr = NULL; - } - } - - if (len > 0 && mgr == NULL) - return -EINVAL; - - if (mgr) - DSSDBG("manager %s found\n", mgr->name); - - if (mgr == ovl->manager) - return size; - - old_mgr = ovl->manager; - - r = dispc_runtime_get(); - if (r) - return r; - - /* detach old manager */ - if (old_mgr) { - r = ovl->unset_manager(ovl); - if (r) { - DSSERR("detach failed\n"); - goto err; - } - - r = old_mgr->apply(old_mgr); - if (r) - goto err; - } - - if (mgr) { - r = ovl->set_manager(ovl, mgr); - if (r) { - DSSERR("Failed to attach overlay\n"); - goto err; - } - - r = mgr->apply(mgr); - if (r) - goto err; - } - - dispc_runtime_put(); - - return size; - -err: - dispc_runtime_put(); - return r; -} - -static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.width, info.height); -} - -static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); -} - -static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.pos_x, info.pos_y); -} - -static ssize_t overlay_position_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.pos_x = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.pos_y = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.out_width, info.out_height); -} - -static ssize_t overlay_output_size_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.out_width = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.out_height = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); -} - -static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int r; - bool enable; - - r = strtobool(buf, &enable); - if (r) - return r; - - if (enable) - r = ovl->enable(ovl); - else - r = ovl->disable(ovl); - - if (r) - return r; - - return size; -} - -static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.global_alpha); -} - -static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.global_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, - char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.pre_mult_alpha); -} - -static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.pre_mult_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); -} - -static ssize_t overlay_zorder_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 zorder; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &zorder); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.zorder = zorder; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -struct overlay_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay *, char *); - ssize_t (*store)(struct omap_overlay *, const char *, size_t); -}; - -#define OVERLAY_ATTR(_name, _mode, _show, _store) \ - struct overlay_attribute overlay_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); -static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, - overlay_manager_show, overlay_manager_store); -static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); -static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); -static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, - overlay_position_show, overlay_position_store); -static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, - overlay_output_size_show, overlay_output_size_store); -static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, - overlay_enabled_show, overlay_enabled_store); -static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, - overlay_global_alpha_show, overlay_global_alpha_store); -static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, - overlay_pre_mult_alpha_show, - overlay_pre_mult_alpha_store); -static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, - overlay_zorder_show, overlay_zorder_store); - -static struct attribute *overlay_sysfs_attrs[] = { - &overlay_attr_name.attr, - &overlay_attr_manager.attr, - &overlay_attr_input_size.attr, - &overlay_attr_screen_width.attr, - &overlay_attr_position.attr, - &overlay_attr_output_size.attr, - &overlay_attr_enabled.attr, - &overlay_attr_global_alpha.attr, - &overlay_attr_pre_mult_alpha.attr, - &overlay_attr_zorder.attr, - NULL -}; - -static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->show) - return -ENOENT; - - return overlay_attr->show(overlay, buf); -} - -static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->store) - return -ENOENT; - - return overlay_attr->store(overlay, buf, size); -} - -static const struct sysfs_ops overlay_sysfs_ops = { - .show = overlay_attr_show, - .store = overlay_attr_store, -}; - -static struct kobj_type overlay_ktype = { - .sysfs_ops = &overlay_sysfs_ops, - .default_attrs = overlay_sysfs_attrs, -}; - int omap_dss_get_num_overlays(void) { return num_overlays; @@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev) ovl->set_overlay_info = &dss_ovl_set_info; ovl->get_overlay_info = &dss_ovl_get_info; ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; + ovl->get_device = &dss_ovl_get_device; ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, - &pdev->dev.kobj, "overlay%d", i); - + r = dss_overlay_kobj_init(ovl, pdev); if (r) DSSERR("failed to create sysfs file\n"); } } -/* connect overlays to the new device, if not already connected. if force - * selected, connect always. */ -void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) -{ - int i; - struct omap_overlay_manager *lcd_mgr; - struct omap_overlay_manager *tv_mgr; - struct omap_overlay_manager *lcd2_mgr = NULL; - struct omap_overlay_manager *lcd3_mgr = NULL; - struct omap_overlay_manager *mgr = NULL; - - lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD); - tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT); - if (dss_has_feature(FEAT_MGR_LCD3)) - lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3); - if (dss_has_feature(FEAT_MGR_LCD2)) - lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2); - - if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) { - if (!lcd3_mgr->device || force) { - if (lcd3_mgr->device) - lcd3_mgr->unset_device(lcd3_mgr); - lcd3_mgr->set_device(lcd3_mgr, dssdev); - mgr = lcd3_mgr; - } - } else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { - if (!lcd2_mgr->device || force) { - if (lcd2_mgr->device) - lcd2_mgr->unset_device(lcd2_mgr); - lcd2_mgr->set_device(lcd2_mgr, dssdev); - mgr = lcd2_mgr; - } - } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC - && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { - if (!lcd_mgr->device || force) { - if (lcd_mgr->device) - lcd_mgr->unset_device(lcd_mgr); - lcd_mgr->set_device(lcd_mgr, dssdev); - mgr = lcd_mgr; - } - } - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - if (!tv_mgr->device || force) { - if (tv_mgr->device) - tv_mgr->unset_device(tv_mgr); - tv_mgr->set_device(tv_mgr, dssdev); - mgr = tv_mgr; - } - } - - if (mgr) { - dispc_runtime_get(); - - for (i = 0; i < dss_feat_get_num_ovls(); i++) { - struct omap_overlay *ovl; - ovl = omap_dss_get_overlay(i); - if (!ovl->manager || force) { - if (ovl->manager) - ovl->unset_manager(ovl); - ovl->set_manager(ovl, mgr); - } - } - - dispc_runtime_put(); - } -} - void dss_uninit_overlays(struct platform_device *pdev) { int i; for (i = 0; i < num_overlays; ++i) { struct omap_overlay *ovl = &overlays[i]; - - kobject_del(&ovl->kobj); - kobject_put(&ovl->kobj); + dss_overlay_kobj_uninit(ovl); } kfree(overlays); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7c087424b634..7282e5af3e1a 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -111,6 +111,13 @@ static struct { struct omap_dss_device *dssdev[2]; struct semaphore bus_lock; + + struct omap_video_timings timings; + int pixel_size; + int data_lines; + struct rfbi_timings intf_timings; + + struct omap_dss_output output; } rfbi; static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) @@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, - u16 height, void (*callback)(void *data), void *data) +static int rfbi_transfer_area(struct omap_dss_device *dssdev, + void (*callback)(void *data), void *data) { u32 l; int r; - struct omap_video_timings timings = { - .hsw = 1, - .hfp = 1, - .hbp = 1, - .vsw = 1, - .vfp = 0, - .vbp = 0, - .x_res = width, - .y_res = height, - }; + struct omap_overlay_manager *mgr = dssdev->output->manager; + u16 width = rfbi.timings.x_res; + u16 height = rfbi.timings.y_res; /*BUG_ON(callback == 0);*/ BUG_ON(rfbi.framedone_callback != NULL); DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dss_mgr_set_timings(dssdev->manager, &timings); + dss_mgr_set_timings(mgr, &rfbi.timings); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) return r; @@ -770,62 +770,45 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines) return 0; } -int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, - int data_lines) +int omap_rfbi_configure(struct omap_dss_device *dssdev) { - return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines); + return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, + rfbi.data_lines); } EXPORT_SYMBOL(omap_rfbi_configure); -int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h) +int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), + void *data) { - u16 dw, dh; - struct omap_video_timings timings = { - .hsw = 1, - .hfp = 1, - .hbp = 1, - .vsw = 1, - .vfp = 0, - .vbp = 0, - .x_res = *w, - .y_res = *h, - }; - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - if (*x > dw || *y > dh) - return -EINVAL; - - if (*x + *w > dw) - return -EINVAL; - - if (*y + *h > dh) - return -EINVAL; - - if (*w == 1) - return -EINVAL; - - if (*w == 0 || *h == 0) - return -EINVAL; - - dss_mgr_set_timings(dssdev->manager, &timings); + return rfbi_transfer_area(dssdev, callback, data); +} +EXPORT_SYMBOL(omap_rfbi_update); - return 0; +void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +{ + rfbi.timings.x_res = w; + rfbi.timings.y_res = h; } -EXPORT_SYMBOL(omap_rfbi_prepare_update); +EXPORT_SYMBOL(omapdss_rfbi_set_size); -int omap_rfbi_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(void *), void *data) +void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size) { - int r; + rfbi.pixel_size = pixel_size; +} +EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size); - r = rfbi_transfer_area(dssdev, w, h, callback, data); +void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) +{ + rfbi.data_lines = data_lines; +} +EXPORT_SYMBOL(omapdss_rfbi_set_data_lines); - return r; +void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, + struct rfbi_timings *timings) +{ + rfbi.intf_timings = *timings; } -EXPORT_SYMBOL(omap_rfbi_update); +EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings); static void rfbi_dump_regs(struct seq_file *s) { @@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s) static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; struct dss_lcd_mgr_config mgr_config; mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; @@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) /* Do we need fifohandcheck for RFBI? */ mgr_config.fifohandcheck = false; - mgr_config.video_port_width = dssdev->ctrl.pixel_size; + mgr_config.video_port_width = rfbi.pixel_size; mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &mgr_config); + dss_mgr_set_lcd_config(mgr, &mgr_config); + + /* + * Set rfbi.timings with default values, the x_res and y_res fields + * are expected to be already configured by the panel driver via + * omapdss_rfbi_set_size() + */ + rfbi.timings.hsw = 1; + rfbi.timings.hfp = 1; + rfbi.timings.hbp = 1; + rfbi.timings.vsw = 1; + rfbi.timings.vfp = 0; + rfbi.timings.vbp = 0; + + rfbi.timings.interlace = false; + rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + + dss_mgr_set_timings(mgr, &rfbi.timings); } int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_output *out = dssdev->output; int r; - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) rfbi_config_lcd_manager(dssdev); - rfbi_configure(dssdev->phy.rfbi.channel, - dssdev->ctrl.pixel_size, - dssdev->phy.rfbi.data_lines); - - rfbi_set_timings(dssdev->phy.rfbi.channel, - &dssdev->ctrl.rfbi_timings); + rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, + rfbi.data_lines); + rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings); return 0; err1: @@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable); static int __init rfbi_init_display(struct omap_dss_device *dssdev) { rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; return 0; } -static void __init rfbi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) continue; - r = rfbi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init rfbi_probe_pdata(struct platform_device *rfbidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = rfbi_find_dssdev(rfbidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&rfbidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + r = rfbi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init rfbi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &rfbi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_DBI; + out->type = OMAP_DISPLAY_TYPE_DBI; + + dss_register_output(out); +} + +static void __exit rfbi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &rfbi.output; + + dss_unregister_output(out); } /* RFBI HW IP initialisation */ @@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev) dss_debugfs_create_file("rfbi", rfbi_dump_regs); + rfbi_init_output(pdev); + rfbi_probe_pdata(pdev); return 0; @@ -1031,8 +1089,12 @@ err_runtime_get: static int __exit omap_rfbihw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + rfbi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return 0; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index f43bfe17b3b6..7760851f6e5d 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -25,6 +25,7 @@ #include <linux/regulator/consumer.h> #include <linux/export.h> #include <linux/platform_device.h> +#include <linux/string.h> #include <video/omapdss.h> #include "dss.h" @@ -34,10 +35,16 @@ static struct { struct regulator *vdds_sdi_reg; struct dss_lcd_mgr_config mgr_config; + struct omap_video_timings timings; + int datapairs; + + struct omap_dss_output output; } sdi; static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; sdi.mgr_config.stallmode = false; @@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) sdi.mgr_config.video_port_width = 24; sdi.mgr_config.lcden_sig_polarity = 1; - dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config); + dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); } int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) { - struct omap_video_timings *t = &dssdev->panel.timings; + struct omap_dss_output *out = dssdev->output; + struct omap_video_timings *t = &sdi.timings; struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err_get_dispc; /* 15.5.9.1.2 */ - dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); if (r) @@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(dssdev->manager, t); + dss_mgr_set_timings(out->manager, t); r = dss_set_clock_div(&dss_cinfo); if (r) @@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(dssdev->manager->id, - &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); - dss_sdi_init(dssdev->phy.sdi.datapairs); + dss_sdi_init(sdi.datapairs); r = dss_sdi_enable(); if (r) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(out->manager); if (r) goto err_mgr_enable; @@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + dss_mgr_disable(mgr); dss_sdi_disable(); @@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omapdss_sdi_display_disable); +void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + sdi.timings = *timings; +} +EXPORT_SYMBOL(omapdss_sdi_set_timings); + +void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) +{ + sdi.datapairs = datapairs; +} +EXPORT_SYMBOL(omapdss_sdi_set_datapairs); + static int __init sdi_init_display(struct omap_dss_device *dssdev) { DSSDBG("SDI init\n"); @@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __init sdi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) continue; - r = sdi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init sdi_probe_pdata(struct platform_device *sdidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = sdi_find_dssdev(sdidev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&sdidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = sdi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init sdi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &sdi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_SDI; + out->type = OMAP_DISPLAY_TYPE_SDI; + + dss_register_output(out); +} + +static void __exit sdi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &sdi.output; + + dss_unregister_output(out); } static int __init omap_sdi_probe(struct platform_device *pdev) { + sdi_init_output(pdev); + sdi_probe_pdata(pdev); return 0; @@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev) static int __exit omap_sdi_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + sdi_uninit_output(pdev); return 0; } diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 3a220877461a..56efa3bb465d 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -36,7 +36,6 @@ #include <linux/pm_runtime.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -300,6 +299,12 @@ static struct { struct regulator *vdda_dac_reg; struct clk *tv_dac_clk; + + struct omap_video_timings timings; + enum omap_dss_venc_type type; + bool invert_polarity; + + struct omap_dss_output output; } venc; static inline void venc_write_reg(int idx, u32 val) @@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config( static int venc_power_on(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; u32 l; int r; + r = venc_runtime_get(); + if (r) + goto err0; + venc_reset(); - venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); + venc_write_config(venc_timings_to_config(&venc.timings)); - dss_set_venc_output(dssdev->phy.venc.type); + dss_set_venc_output(venc.type); dss_set_dac_pwrdn_bgz(1); l = 0; - if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) + if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) l |= 1 << 1; else /* S-Video */ l |= (1 << 0) | (1 << 2); - if (dssdev->phy.venc.invert_polarity == false) + if (venc.invert_polarity == false) l |= 1 << 3; venc_write_reg(VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); + dss_mgr_set_timings(mgr, &venc.timings); r = regulator_enable(venc.vdda_dac_reg); if (r) - goto err; - - if (dssdev->platform_enable) - dssdev->platform_enable(dssdev); + goto err1; - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) - goto err; + goto err2; return 0; -err: +err2: + regulator_disable(venc.vdda_dac_reg); +err1: venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - regulator_disable(venc.vdda_dac_reg); - + venc_runtime_put(); +err0: return r; } static void venc_power_off(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dss_mgr_disable(dssdev->manager); - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + dss_mgr_disable(mgr); regulator_disable(venc.vdda_dac_reg); + + venc_runtime_put(); } unsigned long venc_get_pixel_clock(void) @@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void) return 13500000; } -static ssize_t display_output_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +int omapdss_venc_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *dssdev = to_dss_device(dev); - const char *ret; - - switch (dssdev->phy.venc.type) { - case OMAP_DSS_VENC_TYPE_COMPOSITE: - ret = "composite"; - break; - case OMAP_DSS_VENC_TYPE_SVIDEO: - ret = "svideo"; - break; - default: - return -EINVAL; - } - - return snprintf(buf, PAGE_SIZE, "%s\n", ret); -} + struct omap_dss_output *out = dssdev->output; + int r; -static ssize_t display_output_type_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - enum omap_dss_venc_type new_type; - - if (sysfs_streq("composite", buf)) - new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; - else if (sysfs_streq("svideo", buf)) - new_type = OMAP_DSS_VENC_TYPE_SVIDEO; - else - return -EINVAL; + DSSDBG("venc_display_enable\n"); mutex_lock(&venc.venc_lock); - if (dssdev->phy.venc.type != new_type) { - dssdev->phy.venc.type = new_type; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - venc_power_off(dssdev); - venc_power_on(dssdev); - } + if (out == NULL || out->manager == NULL) { + DSSERR("Failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err0; } - mutex_unlock(&venc.venc_lock); - - return size; -} - -static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, - display_output_type_show, display_output_type_store); - -/* driver */ -static int venc_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.timings = omap_dss_pal_timings; - - return device_create_file(&dssdev->dev, &dev_attr_output_type); -} - -static void venc_panel_remove(struct omap_dss_device *dssdev) -{ - device_remove_file(&dssdev->dev, &dev_attr_output_type); -} - -static int venc_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - DSSDBG("venc_enable_display\n"); - - mutex_lock(&venc.venc_lock); - r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); goto err0; } - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - r = -EINVAL; - goto err1; - } + if (dssdev->platform_enable) + dssdev->platform_enable(dssdev); - r = venc_runtime_get(); - if (r) - goto err1; r = venc_power_on(dssdev); if (r) - goto err2; + goto err1; venc.wss_data = 0; - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - mutex_unlock(&venc.venc_lock); + return 0; -err2: - venc_runtime_put(); err1: + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); omap_dss_stop_device(dssdev); err0: mutex_unlock(&venc.venc_lock); - return r; } -static void venc_panel_disable(struct omap_dss_device *dssdev) +void omapdss_venc_display_disable(struct omap_dss_device *dssdev) { - DSSDBG("venc_disable_display\n"); + DSSDBG("venc_display_disable\n"); mutex_lock(&venc.venc_lock); - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) - goto end; - - if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { - /* suspended is the same as disabled with venc */ - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - goto end; - } - venc_power_off(dssdev); - venc_runtime_put(); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - omap_dss_stop_device(dssdev); -end: - mutex_unlock(&venc.venc_lock); -} -static int venc_panel_suspend(struct omap_dss_device *dssdev) -{ - venc_panel_disable(dssdev); - return 0; -} + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); -static int venc_panel_resume(struct omap_dss_device *dssdev) -{ - return venc_panel_enable(dssdev); + mutex_unlock(&venc.venc_lock); } -static void venc_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +void omapdss_venc_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { DSSDBG("venc_set_timings\n"); + mutex_lock(&venc.venc_lock); + /* Reset WSS data when the TV standard changes. */ - if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings))) + if (memcmp(&venc.timings, timings, sizeof(*timings))) venc.wss_data = 0; - dssdev->panel.timings = *timings; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - /* turn the venc off and on to get new timings to use */ - venc_panel_disable(dssdev); - venc_panel_enable(dssdev); - } else { - dss_mgr_set_timings(dssdev->manager, timings); - } + venc.timings = *timings; + + mutex_unlock(&venc.venc_lock); } -static int venc_check_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +int omapdss_venc_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { DSSDBG("venc_check_timings\n"); @@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev, return -EINVAL; } -static u32 venc_get_wss(struct omap_dss_device *dssdev) +u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) { /* Invert due to VENC_L21_WC_CTL:INV=1 */ return (venc.wss_data >> 8) ^ 0xfffff; } -static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) +int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { const struct venc_config *config; int r; @@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) mutex_lock(&venc.venc_lock); - config = venc_timings_to_config(&dssdev->panel.timings); + config = venc_timings_to_config(&venc.timings); /* Invert due to VENC_L21_WC_CTL:INV=1 */ venc.wss_data = (wss ^ 0xfffff) << 8; @@ -703,30 +622,25 @@ err: return r; } -static struct omap_dss_driver venc_driver = { - .probe = venc_panel_probe, - .remove = venc_panel_remove, +void omapdss_venc_set_type(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type) +{ + mutex_lock(&venc.venc_lock); - .enable = venc_panel_enable, - .disable = venc_panel_disable, - .suspend = venc_panel_suspend, - .resume = venc_panel_resume, + venc.type = type; - .get_resolution = omapdss_default_get_resolution, - .get_recommended_bpp = omapdss_default_get_recommended_bpp, + mutex_unlock(&venc.venc_lock); +} - .set_timings = venc_set_timings, - .check_timings = venc_check_timings, +void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, + bool invert_polarity) +{ + mutex_lock(&venc.venc_lock); - .get_wss = venc_get_wss, - .set_wss = venc_set_wss, + venc.invert_polarity = invert_polarity; - .driver = { - .name = "venc", - .owner = THIS_MODULE, - }, -}; -/* driver end */ + mutex_unlock(&venc.venc_lock); +} static int __init venc_init_display(struct omap_dss_device *dssdev) { @@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) - if (cpu_is_omap44xx()) { - seq_printf(s, "VENC currently disabled on OMAP44xx\n"); - return; - } - if (venc_runtime_get()) return; @@ -832,10 +741,14 @@ static void venc_put_clocks(void) clk_put(venc.tv_dac_clk); } -static void __init venc_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int r, i; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) continue; - r = venc_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init venc_probe_pdata(struct platform_device *vencdev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = venc_find_dssdev(vencdev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&vencdev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + + r = venc_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init venc_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &venc.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_VENC; + out->type = OMAP_DISPLAY_TYPE_VENC; + + dss_register_output(out); +} + +static void __exit venc_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &venc.output; + + dss_unregister_output(out); } /* VENC HW IP initialisation */ @@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev) venc_runtime_put(); - r = omap_dss_register_driver(&venc_driver); + r = venc_panel_init(); if (r) - goto err_reg_panel_driver; + goto err_panel_init; dss_debugfs_create_file("venc", venc_dump_regs); + venc_init_output(pdev); + venc_probe_pdata(pdev); return 0; -err_reg_panel_driver: +err_panel_init: err_runtime_get: pm_runtime_disable(&pdev->dev); venc_put_clocks(); @@ -916,14 +883,16 @@ err_runtime_get: static int __exit omap_venchw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); if (venc.vdda_dac_reg != NULL) { regulator_put(venc.vdda_dac_reg); venc.vdda_dac_reg = NULL; } - omap_dss_unregister_driver(&venc_driver); + venc_panel_exit(); + + venc_uninit_output(pdev); pm_runtime_disable(&pdev->dev); venc_put_clocks(); @@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = { int __init venc_init_platform_driver(void) { - if (cpu_is_omap44xx()) - return 0; - return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); } void __exit venc_uninit_platform_driver(void) { - if (cpu_is_omap44xx()) - return; - platform_driver_unregister(&omap_venchw_driver); } diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c new file mode 100644 index 000000000000..d55b8784ecfd --- /dev/null +++ b/drivers/video/omap2/dss/venc_panel.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * VENC panel driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <linux/module.h> + +#include <video/omapdss.h> + +#include "dss.h" + +static struct { + struct mutex lock; +} venc_panel; + +static ssize_t display_output_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + const char *ret; + + switch (dssdev->phy.venc.type) { + case OMAP_DSS_VENC_TYPE_COMPOSITE: + ret = "composite"; + break; + case OMAP_DSS_VENC_TYPE_SVIDEO: + ret = "svideo"; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", ret); +} + +static ssize_t display_output_type_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + enum omap_dss_venc_type new_type; + + if (sysfs_streq("composite", buf)) + new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; + else if (sysfs_streq("svideo", buf)) + new_type = OMAP_DSS_VENC_TYPE_SVIDEO; + else + return -EINVAL; + + mutex_lock(&venc_panel.lock); + + if (dssdev->phy.venc.type != new_type) { + dssdev->phy.venc.type = new_type; + omapdss_venc_set_type(dssdev, new_type); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + omapdss_venc_display_disable(dssdev); + omapdss_venc_display_enable(dssdev); + } + } + + mutex_unlock(&venc_panel.lock); + + return size; +} + +static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, + display_output_type_show, display_output_type_store); + +static int venc_panel_probe(struct omap_dss_device *dssdev) +{ + /* set default timings to PAL */ + const struct omap_video_timings default_timings = { + .x_res = 720, + .y_res = 574, + .pixel_clock = 13500, + .hsw = 64, + .hfp = 12, + .hbp = 68, + .vsw = 5, + .vfp = 5, + .vbp = 41, + + .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, + .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, + + .interlace = true, + }; + + mutex_init(&venc_panel.lock); + + dssdev->panel.timings = default_timings; + + return device_create_file(&dssdev->dev, &dev_attr_output_type); +} + +static void venc_panel_remove(struct omap_dss_device *dssdev) +{ + device_remove_file(&dssdev->dev, &dev_attr_output_type); +} + +static int venc_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "venc_panel_enable\n"); + + mutex_lock(&venc_panel.lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } + + omapdss_venc_set_timings(dssdev, &dssdev->panel.timings); + omapdss_venc_set_type(dssdev, dssdev->phy.venc.type); + omapdss_venc_invert_vid_out_polarity(dssdev, + dssdev->phy.venc.invert_polarity); + + r = omapdss_venc_display_enable(dssdev); + if (r) + goto err; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&venc_panel.lock); + + return 0; +err: + mutex_unlock(&venc_panel.lock); + + return r; +} + +static void venc_panel_disable(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "venc_panel_disable\n"); + + mutex_lock(&venc_panel.lock); + + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) + goto end; + + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { + /* suspended is the same as disabled with venc */ + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + goto end; + } + + omapdss_venc_display_disable(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +end: + mutex_unlock(&venc_panel.lock); +} + +static int venc_panel_suspend(struct omap_dss_device *dssdev) +{ + venc_panel_disable(dssdev); + return 0; +} + +static int venc_panel_resume(struct omap_dss_device *dssdev) +{ + return venc_panel_enable(dssdev); +} + +static void venc_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); + + mutex_lock(&venc_panel.lock); + + omapdss_venc_set_timings(dssdev, timings); + dssdev->panel.timings = *timings; + + mutex_unlock(&venc_panel.lock); +} + +static int venc_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); + + return omapdss_venc_check_timings(dssdev, timings); +} + +static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); + + return omapdss_venc_get_wss(dssdev); +} + +static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) +{ + dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); + + return omapdss_venc_set_wss(dssdev, wss); +} + +static struct omap_dss_driver venc_driver = { + .probe = venc_panel_probe, + .remove = venc_panel_remove, + + .enable = venc_panel_enable, + .disable = venc_panel_disable, + .suspend = venc_panel_suspend, + .resume = venc_panel_resume, + + .get_resolution = omapdss_default_get_resolution, + .get_recommended_bpp = omapdss_default_get_recommended_bpp, + + .set_timings = venc_panel_set_timings, + .check_timings = venc_panel_check_timings, + + .get_wss = venc_panel_get_wss, + .set_wss = venc_panel_set_wss, + + .driver = { + .name = "venc", + .owner = THIS_MODULE, + }, +}; + +int venc_panel_init(void) +{ + return omap_dss_register_driver(&venc_driver); +} + +void venc_panel_exit(void) +{ + omap_dss_unregister_driver(&venc_driver); +} diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index c6cf372d22c5..606b89f12351 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -599,6 +599,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); + struct omap_overlay_manager *mgr; union { struct omapfb_update_window_old uwnd_o; @@ -786,12 +787,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); - if (!display) { + if (!display && !display->output && !display->output->manager) { r = -EINVAL; break; } - r = display->manager->wait_for_vsync(display->manager); + mgr = display->output->manager; + + r = mgr->wait_for_vsync(mgr); break; case OMAPFB_WAITFORGO: diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 15373f4aee19..16db1589bd91 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1593,6 +1593,20 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) return 0; } +static void omapfb_clear_fb(struct fb_info *fbi) +{ + const struct fb_fillrect rect = { + .dx = 0, + .dy = 0, + .width = fbi->var.xres_virtual, + .height = fbi->var.yres_virtual, + .color = 0, + .rop = ROP_COPY, + }; + + cfb_fillrect(fbi, &rect); +} + int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) { struct omapfb_info *ofbi = FB2OFB(fbi); @@ -1662,6 +1676,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) goto err; } + omapfb_clear_fb(fbi); + return 0; err: omapfb_free_fbmem(fbi); @@ -1946,6 +1962,16 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) } } + for (i = 0; i < fbdev->num_fbs; i++) { + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + if (ofbi->region->size == 0) + continue; + + omapfb_clear_fb(fbi); + } + DBG("fb_infos initialized\n"); for (i = 0; i < fbdev->num_fbs; i++) { @@ -2354,6 +2380,7 @@ static int __init omapfb_probe(struct platform_device *pdev) struct omap_overlay *ovl; struct omap_dss_device *def_display; struct omap_dss_device *dssdev; + struct omap_dss_device *ovl_device; DBG("omapfb_probe\n"); @@ -2427,8 +2454,9 @@ static int __init omapfb_probe(struct platform_device *pdev) /* gfx overlay should be the default one. find a display * connected to that, and use it as default display */ ovl = omap_dss_get_overlay(0); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; + ovl_device = ovl->get_device(ovl); + if (ovl_device) { + def_display = ovl_device; } else { dev_warn(&pdev->dev, "cannot find default display\n"); def_display = NULL; diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 30361a09aecd..5ced9b334d35 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -148,8 +148,9 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) /* XXX: returns the display connected to first attached overlay */ for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->manager) - return ofbi->overlays[i]->manager->device; + struct omap_overlay *ovl = ofbi->overlays[i]; + + return ovl->get_device(ovl); } return NULL; diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 87e421e25afe..f2b15c4a75bc 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -34,7 +34,6 @@ #include <asm/setup.h> #include <plat/vram.h> -#include <plat/dma.h> #ifdef DEBUG #define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__) @@ -250,59 +249,6 @@ int omap_vram_reserve(unsigned long paddr, size_t size) } EXPORT_SYMBOL(omap_vram_reserve); -static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data) -{ - struct completion *compl = data; - complete(compl); -} - -static int _omap_vram_clear(u32 paddr, unsigned pages) -{ - struct completion compl; - unsigned elem_count; - unsigned frame_count; - int r; - int lch; - - init_completion(&compl); - - r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA", - _omap_vram_dma_cb, - &compl, &lch); - if (r) { - pr_err("VRAM: request_dma failed for memory clear\n"); - return -EBUSY; - } - - elem_count = pages * PAGE_SIZE / 4; - frame_count = 1; - - omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32, - elem_count, frame_count, - OMAP_DMA_SYNC_ELEMENT, - 0, 0); - - omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC, - paddr, 0, 0); - - omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000); - - omap_start_dma(lch); - - if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) { - omap_stop_dma(lch); - pr_err("VRAM: dma timeout while clearing memory\n"); - r = -EIO; - goto err; - } - - r = 0; -err: - omap_free_dma(lch); - - return r; -} - static int _omap_vram_alloc(unsigned pages, unsigned long *paddr) { struct vram_region *rm; @@ -337,8 +283,6 @@ found: *paddr = start; - _omap_vram_clear(start, pages); - return 0; } diff --git a/drivers/video/pnx4008/Makefile b/drivers/video/pnx4008/Makefile deleted file mode 100644 index 636aaccf01fd..000000000000 --- a/drivers/video/pnx4008/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the new PNX4008 framebuffer device driver -# - -obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o -obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o - diff --git a/drivers/video/pnx4008/dum.h b/drivers/video/pnx4008/dum.h deleted file mode 100644 index 1234d4375d92..000000000000 --- a/drivers/video/pnx4008/dum.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * linux/drivers/video/pnx4008/dum.h - * - * Internal header for SDUM - * - * 2005 (c) Koninklijke Philips N.V. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __PNX008_DUM_H__ -#define __PNX008_DUM_H__ - -#include <mach/platform.h> - -#define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE) -#define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE) - -/* DUM CFG ADDRESSES */ -#define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00) -#define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00) -#define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04) -#define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08) -#define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C) -#define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10) - -#define CH_MARG (0x100 / sizeof(u32)) -#define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG)) -#define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG)) -#define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG)) -#define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG)) -#define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG)) - -#define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00) -#define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04) -#define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08) -#define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C) -#define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10) -#define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14) -#define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18) -#define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20) -#define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24) -#define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28) -#define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30) -#define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34) -#define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38) -#define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C) -#define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40) -#define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44) -#define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48) -#define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C) -#define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50) - -#define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR)) -#define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR)) -#define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR)) -#define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR)) -#define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR)) -#define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR)) -#define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR)) -#define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR)) -#define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR)) -#define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR)) -#define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR)) -#define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR)) -#define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR)) -#define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR)) -#define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR)) -#define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR)) -#define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR)) -#define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR)) -#define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR)) - -/* DUM SLAVE ADDRESSES */ -#define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000) -#define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000) -#define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004) -#define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008) -#define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C) - -#define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR)) -#define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR)) -#define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR)) -#define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR)) -#define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR)) -#define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR)) - -/* Sony display register addresses */ -#define DISP_0_REG (0x00) -#define DISP_1_REG (0x01) -#define DISP_CAL_REG (0x20) -#define DISP_ID_REG (0x2A) -#define DISP_XMIN_L_REG (0x30) -#define DISP_XMIN_H_REG (0x31) -#define DISP_YMIN_REG (0x32) -#define DISP_XMAX_L_REG (0x34) -#define DISP_XMAX_H_REG (0x35) -#define DISP_YMAX_REG (0x36) -#define DISP_SYNC_EN_REG (0x38) -#define DISP_SYNC_RISE_L_REG (0x3C) -#define DISP_SYNC_RISE_H_REG (0x3D) -#define DISP_SYNC_FALL_L_REG (0x3E) -#define DISP_SYNC_FALL_H_REG (0x3F) -#define DISP_PIXEL_REG (0x0B) -#define DISP_DUMMY1_REG (0x28) -#define DISP_DUMMY2_REG (0x29) -#define DISP_TIMING_REG (0x98) -#define DISP_DUMP_REG (0x99) - -/* Sony display constants */ -#define SONY_ID1 (0x22) -#define SONY_ID2 (0x23) - -/* Philips display register addresses */ -#define PH_DISP_ORIENT_REG (0x003) -#define PH_DISP_YPOINT_REG (0x200) -#define PH_DISP_XPOINT_REG (0x201) -#define PH_DISP_PIXEL_REG (0x202) -#define PH_DISP_YMIN_REG (0x406) -#define PH_DISP_YMAX_REG (0x407) -#define PH_DISP_XMIN_REG (0x408) -#define PH_DISP_XMAX_REG (0x409) - -/* Misc constants */ -#define NO_VALID_DISPLAY_FOUND (0) -#define DISPLAY2_IS_NOT_CONNECTED (0) - -/* register values */ -#define V_BAC_ENABLE (BIT(0)) -#define V_BAC_DISABLE_IDLE (BIT(1)) -#define V_BAC_DISABLE_TRIG (BIT(2)) -#define V_DUM_RESET (BIT(3)) -#define V_MUX_RESET (BIT(4)) -#define BAC_ENABLED (BIT(0)) -#define BAC_DISABLED 0 - -/* Sony LCD commands */ -#define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG) -#define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG) -#define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG) -#define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG) -#define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG) -#define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG) -#define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG) -#define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG) - -enum { - PAD_NONE, - PAD_512, - PAD_1024 -}; - -enum { - RGB888, - RGB666, - RGB565, - BGR565, - ARGB1555, - ABGR1555, - ARGB4444, - ABGR4444 -}; - -struct dum_setup { - int sync_neg_edge; - int round_robin; - int mux_int; - int synced_dirty_flag_int; - int dirty_flag_int; - int error_int; - int pf_empty_int; - int sf_empty_int; - int bac_dis_int; - u32 dirty_base_adr; - u32 command_base_adr; - u32 sync_clk_div; - int sync_output; - u32 sync_restart_val; - u32 set_sync_high; - u32 set_sync_low; -}; - -struct dum_ch_setup { - int disp_no; - u32 xmin; - u32 ymin; - u32 xmax; - u32 ymax; - int xmirror; - int ymirror; - int rotate; - u32 minadr; - u32 maxadr; - u32 dirtybuffer; - int pad; - int format; - int hwdirty; - int slave_trans; -}; - -struct disp_window { - u32 xmin_l; - u32 xmin_h; - u32 ymin; - u32 xmax_l; - u32 xmax_h; - u32 ymax; -}; - -#endif /* #ifndef __PNX008_DUM_H__ */ diff --git a/drivers/video/pnx4008/fbcommon.h b/drivers/video/pnx4008/fbcommon.h deleted file mode 100644 index 4ebc87dafafb..000000000000 --- a/drivers/video/pnx4008/fbcommon.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2005 Philips Semiconductors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html -*/ - -#define QCIF_W (176) -#define QCIF_H (144) - -#define CIF_W (352) -#define CIF_H (288) - -#define LCD_X_RES 208 -#define LCD_Y_RES 320 -#define LCD_X_PAD 256 -#define LCD_BBP 4 /* Bytes Per Pixel */ - -#define DISP_MAX_X_SIZE (320) -#define DISP_MAX_Y_SIZE (208) - -#define RETURNVAL_BASE (0x400) - -enum fb_ioctl_returntype { - ENORESOURCESLEFT = RETURNVAL_BASE, - ERESOURCESNOTFREED, - EPROCNOTOWNER, - EFBNOTOWNER, - ECOPYFAILED, - EIOREMAPFAILED, -}; diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c deleted file mode 100644 index 6d30428e9cf9..000000000000 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * drivers/video/pnx4008/pnxrgbfb.c - * - * PNX4008's framebuffer support - * - * Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> - * Based on Philips Semiconductors's code - * - * Copyrght (c) 2005 MontaVista Software, Inc. - * Copyright (c) 2005 Philips Semiconductors - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/platform_device.h> - -#include "sdum.h" -#include "fbcommon.h" - -static u32 colreg[16]; - -static struct fb_var_screeninfo rgbfb_var __initdata = { - .xres = LCD_X_RES, - .yres = LCD_Y_RES, - .xres_virtual = LCD_X_RES, - .yres_virtual = LCD_Y_RES, - .bits_per_pixel = 32, - .red.offset = 16, - .red.length = 8, - .green.offset = 8, - .green.length = 8, - .blue.offset = 0, - .blue.length = 8, - .left_margin = 0, - .right_margin = 0, - .upper_margin = 0, - .lower_margin = 0, - .vmode = FB_VMODE_NONINTERLACED, -}; -static struct fb_fix_screeninfo rgbfb_fix __initdata = { - .id = "RGBFB", - .line_length = LCD_X_RES * LCD_BBP, - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, -}; - -static int channel_owned; - -static int no_cursor(struct fb_info *info, struct fb_cursor *cursor) -{ - return 0; -} - -static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno > 15) - return 1; - - colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) | - ((blue & 0xff00) >> 8); - return 0; -} - -static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - return pnx4008_sdum_mmap(info, vma, NULL); -} - -static struct fb_ops rgbfb_ops = { - .fb_mmap = rgbfb_mmap, - .fb_setcolreg = rgbfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - -static int rgbfb_remove(struct platform_device *pdev) -{ - struct fb_info *info = platform_get_drvdata(pdev); - - if (info) { - unregister_framebuffer(info); - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - platform_set_drvdata(pdev, NULL); - } - - pnx4008_free_dum_channel(channel_owned, pdev->id); - pnx4008_set_dum_exit_notification(pdev->id); - - return 0; -} - -static int __devinit rgbfb_probe(struct platform_device *pdev) -{ - struct fb_info *info; - struct dumchannel_uf chan_uf; - int ret; - char *option; - - info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); - if (!info) { - ret = -ENOMEM; - goto err; - } - - pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base, - (dma_addr_t *) &rgbfb_fix.smem_start, - &rgbfb_fix.smem_len); - - if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0) - goto err0; - else { - channel_owned = ret; - chan_uf.channelnr = channel_owned; - chan_uf.dirty = (u32 *) NULL; - chan_uf.source = (u32 *) rgbfb_fix.smem_start; - chan_uf.x_offset = 0; - chan_uf.y_offset = 0; - chan_uf.width = LCD_X_RES; - chan_uf.height = LCD_Y_RES; - - if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0) - goto err1; - - if ((ret = - pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON, - pdev->id)) < 0) - goto err1; - - if ((ret = - pnx4008_set_dum_channel_dirty_detect(channel_owned, - CONF_DIRTYDETECTION_ON, - pdev->id)) < 0) - goto err1; - } - - if (!fb_get_options("pnxrgbfb", &option) && option && - !strcmp(option, "nocursor")) - rgbfb_ops.fb_cursor = no_cursor; - - info->node = -1; - info->flags = FBINFO_FLAG_DEFAULT; - info->fbops = &rgbfb_ops; - info->fix = rgbfb_fix; - info->var = rgbfb_var; - info->screen_size = rgbfb_fix.smem_len; - info->pseudo_palette = info->par; - info->par = NULL; - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret < 0) - goto err1; - - ret = register_framebuffer(info); - if (ret < 0) - goto err2; - platform_set_drvdata(pdev, info); - - return 0; - -err2: - fb_dealloc_cmap(&info->cmap); -err1: - pnx4008_free_dum_channel(channel_owned, pdev->id); -err0: - framebuffer_release(info); -err: - return ret; -} - -static struct platform_driver rgbfb_driver = { - .driver = { - .name = "pnx4008-rgbfb", - }, - .probe = rgbfb_probe, - .remove = rgbfb_remove, -}; - -module_platform_driver(rgbfb_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c deleted file mode 100644 index c5c741452cac..000000000000 --- a/drivers/video/pnx4008/sdum.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * drivers/video/pnx4008/sdum.c - * - * Display Update Master support - * - * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> - * Vitaly Wool <vitalywool@gmail.com> - * Based on Philips Semiconductors's code - * - * Copyrght (c) 2005-2006 MontaVista Software, Inc. - * Copyright (c) 2005 Philips Semiconductors - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/gfp.h> -#include <asm/uaccess.h> -#include <asm/gpio.h> - -#include "sdum.h" -#include "fbcommon.h" -#include "dum.h" - -/* Framebuffers we have */ - -static struct pnx4008_fb_addr { - int fb_type; - long addr_offset; - long fb_length; -} fb_addr[] = { - [0] = { - FB_TYPE_YUV, 0, 0xB0000 - }, - [1] = { - FB_TYPE_RGB, 0xB0000, 0x50000 - }, -}; - -static struct dum_data { - u32 lcd_phys_start; - u32 lcd_virt_start; - u32 slave_phys_base; - u32 *slave_virt_base; - int fb_owning_channel[MAX_DUM_CHANNELS]; - struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS]; -} dum_data; - -/* Different local helper functions */ - -static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup) -{ - return (ch_setup->xmax - ch_setup->xmin + 1); -} - -static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup) -{ - return (ch_setup->ymax - ch_setup->ymin + 1); -} - -static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup) -{ - return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup)); -} - -static u32 nof_bytes(struct dum_ch_setup *ch_setup) -{ - u32 r = nof_pixels_dxy(ch_setup); - switch (ch_setup->format) { - case RGB888: - case RGB666: - r *= 4; - break; - - default: - r *= 2; - break; - } - return r; -} - -static u32 build_command(int disp_no, u32 reg, u32 val) -{ - return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) | - (reg << 0)); -} - -static u32 build_double_index(int disp_no, u32 val) -{ - return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0)); -} - -static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw) -{ - dw->ymin = ch_setup->ymin; - dw->ymax = ch_setup->ymax; - dw->xmin_l = ch_setup->xmin & 0xFF; - dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8; - dw->xmax_l = ch_setup->xmax & 0xFF; - dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8; -} - -static int put_channel(struct dumchannel chan) -{ - int i = chan.channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else { - DUM_CH_MIN(i) = chan.dum_ch_min; - DUM_CH_MAX(i) = chan.dum_ch_max; - DUM_CH_CONF(i) = chan.dum_ch_conf; - DUM_CH_CTRL(i) = chan.dum_ch_ctrl; - } - - return 0; -} - -static void clear_channel(int channr) -{ - struct dumchannel chan; - - chan.channelnr = channr; - chan.dum_ch_min = 0; - chan.dum_ch_max = 0; - chan.dum_ch_conf = 0; - chan.dum_ch_ctrl = 0; - - put_channel(chan); -} - -static int put_cmd_string(struct cmdstring cmds) -{ - u16 *cmd_str_virtaddr; - u32 *cmd_ptr0_virtaddr; - u32 cmd_str_physaddr; - - int i = cmds.channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else if ((cmd_ptr0_virtaddr = - (int *)ioremap_nocache(DUM_COM_BASE, - sizeof(int) * MAX_DUM_CHANNELS)) == - NULL) - return -EIOREMAPFAILED; - else { - cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]); - if ((cmd_str_virtaddr = - (u16 *) ioremap_nocache(cmd_str_physaddr, - sizeof(cmds))) == NULL) { - iounmap(cmd_ptr0_virtaddr); - return -EIOREMAPFAILED; - } else { - int t; - for (t = 0; t < 8; t++) - iowrite16(*((u16 *)&cmds.prestringlen + t), - cmd_str_virtaddr + t); - - for (t = 0; t < cmds.prestringlen / 2; t++) - iowrite16(*((u16 *)&cmds.precmd + t), - cmd_str_virtaddr + t + 8); - - for (t = 0; t < cmds.poststringlen / 2; t++) - iowrite16(*((u16 *)&cmds.postcmd + t), - cmd_str_virtaddr + t + 8 + - cmds.prestringlen / 2); - - iounmap(cmd_ptr0_virtaddr); - iounmap(cmd_str_virtaddr); - } - } - - return 0; -} - -static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup) -{ - struct cmdstring cmds_c; - struct cmdstring *cmds = &cmds_c; - struct disp_window dw; - int standard; - u32 orientation = 0; - struct dumchannel chan = { 0 }; - int ret; - - if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) { - standard = 0; - - orientation = BIT(1); /* always set 9-bit-bus */ - if (ch_setup->xmirror) - orientation |= BIT(4); - if (ch_setup->ymirror) - orientation |= BIT(3); - if (ch_setup->rotate) - orientation |= BIT(0); - } else - standard = 1; - - cmds->channelnr = ch_no; - - /* build command string header */ - if (standard) { - cmds->prestringlen = 32; - cmds->poststringlen = 0; - } else { - cmds->prestringlen = 48; - cmds->poststringlen = 16; - } - - cmds->format = - (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format)); - cmds->reserved = 0x0; - cmds->startaddr_low = (ch_setup->minadr & 0xFFFF); - cmds->startaddr_high = (ch_setup->minadr >> 16); - - if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0) - && (ch_setup->xmin == 0) - && (ch_setup->ymin == 0) && (ch_setup->xmax == 0) - && (ch_setup->ymax == 0)) { - cmds->pixdatlen_low = 0; - cmds->pixdatlen_high = 0; - } else { - u32 nbytes = nof_bytes(ch_setup); - cmds->pixdatlen_low = (nbytes & 0xFFFF); - cmds->pixdatlen_high = (nbytes >> 16); - } - - if (ch_setup->slave_trans) - cmds->pixdatlen_high |= BIT(15); - - /* build pre-string */ - build_disp_window(ch_setup, &dw); - - if (standard) { - cmds->precmd[0] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99); - cmds->precmd[1] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - dw.xmin_l); - cmds->precmd[2] = - build_command(ch_setup->disp_no, DISP_XMIN_H_REG, - dw.xmin_h); - cmds->precmd[3] = - build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); - cmds->precmd[4] = - build_command(ch_setup->disp_no, DISP_XMAX_L_REG, - dw.xmax_l); - cmds->precmd[5] = - build_command(ch_setup->disp_no, DISP_XMAX_H_REG, - dw.xmax_h); - cmds->precmd[6] = - build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); - cmds->precmd[7] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - } else { - if (dw.xmin_l == ch_no) - cmds->precmd[0] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - 0x99); - else - cmds->precmd[0] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - ch_no); - - cmds->precmd[1] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - dw.xmin_l); - cmds->precmd[2] = - build_command(ch_setup->disp_no, DISP_XMIN_H_REG, - dw.xmin_h); - cmds->precmd[3] = - build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); - cmds->precmd[4] = - build_command(ch_setup->disp_no, DISP_XMAX_L_REG, - dw.xmax_l); - cmds->precmd[5] = - build_command(ch_setup->disp_no, DISP_XMAX_H_REG, - dw.xmax_h); - cmds->precmd[6] = - build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); - cmds->precmd[7] = - build_command(ch_setup->disp_no, DISP_1_REG, orientation); - cmds->precmd[8] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->precmd[9] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->precmd[0xA] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->precmd[0xB] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->postcmd[0] = - build_command(ch_setup->disp_no, DISP_1_REG, BIT(1)); - cmds->postcmd[1] = - build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1); - cmds->postcmd[2] = - build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2); - cmds->postcmd[3] = - build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3); - } - - if ((ret = put_cmd_string(cmds_c)) != 0) { - return ret; - } - - chan.channelnr = cmds->channelnr; - chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr; - chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr; - chan.dum_ch_conf = 0x002; - chan.dum_ch_ctrl = 0x04; - - put_channel(chan); - - return 0; -} - -static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer, - u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h) -{ - - struct dum_ch_setup k; - int ret; - - /* keep width & height within display area */ - if ((xpos + w) > DISP_MAX_X_SIZE) - w = DISP_MAX_X_SIZE - xpos; - - if ((ypos + h) > DISP_MAX_Y_SIZE) - h = DISP_MAX_Y_SIZE - ypos; - - /* assume 1 display only */ - k.disp_no = 0; - k.xmin = xpos; - k.ymin = ypos; - k.xmax = xpos + (w - 1); - k.ymax = ypos + (h - 1); - - /* adjust min and max values if necessary */ - if (k.xmin > DISP_MAX_X_SIZE - 1) - k.xmin = DISP_MAX_X_SIZE - 1; - if (k.ymin > DISP_MAX_Y_SIZE - 1) - k.ymin = DISP_MAX_Y_SIZE - 1; - - if (k.xmax > DISP_MAX_X_SIZE - 1) - k.xmax = DISP_MAX_X_SIZE - 1; - if (k.ymax > DISP_MAX_Y_SIZE - 1) - k.ymax = DISP_MAX_Y_SIZE - 1; - - k.xmirror = 0; - k.ymirror = 0; - k.rotate = 0; - k.minadr = (u32) frame_buffer; - k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2)); - k.pad = PAD_1024; - k.dirtybuffer = (u32) dirty_buffer; - k.format = RGB888; - k.hwdirty = 0; - k.slave_trans = 0; - - ret = dum_ch_setup(ch_no, &k); - - return ret; -} - -static void lcd_reset(void) -{ - u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE); - - udelay(1); - iowrite32(BIT(19), &dum_pio_base[2]); - udelay(1); - iowrite32(BIT(19), &dum_pio_base[1]); - udelay(1); -} - -static int dum_init(struct platform_device *pdev) -{ - struct clk *clk; - - /* enable DUM clock */ - clk = clk_get(&pdev->dev, "dum_ck"); - if (IS_ERR(clk)) { - printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n"); - return PTR_ERR(clk); - } - - clk_set_rate(clk, 1); - clk_put(clk); - - DUM_CTRL = V_DUM_RESET; - - /* set priority to "round-robin". All other params to "false" */ - DUM_CONF = BIT(9); - - /* Display 1 */ - DUM_WTCFG1 = PNX4008_DUM_WT_CFG; - DUM_RTCFG1 = PNX4008_DUM_RT_CFG; - DUM_TCFG = PNX4008_DUM_T_CFG; - - return 0; -} - -static void dum_chan_init(void) -{ - int i = 0, ch = 0; - u32 *cmdptrs; - u32 *cmdstrings; - - DUM_COM_BASE = - CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS; - - if ((cmdptrs = - (u32 *) ioremap_nocache(DUM_COM_BASE, - sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL) - return; - - for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++) - iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch, - cmdptrs + ch); - - for (ch = 0; ch < MAX_DUM_CHANNELS; ch++) - clear_channel(ch); - - /* Clear the cmdstrings */ - cmdstrings = - (u32 *)ioremap_nocache(*cmdptrs, - BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS); - - if (!cmdstrings) - goto out; - - for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32); - i++) - iowrite32(0, cmdstrings + i); - - iounmap((u32 *)cmdstrings); - -out: - iounmap((u32 *)cmdptrs); -} - -static void lcd_init(void) -{ - lcd_reset(); - - DUM_OUTP_FORMAT1 = 0; /* RGB666 */ - - udelay(1); - iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base); - udelay(1); -} - -/* Interface exported to framebuffer drivers */ - -int pnx4008_get_fb_addresses(int fb_type, void **virt_addr, - dma_addr_t *phys_addr, int *fb_length) -{ - int i; - int ret = -1; - for (i = 0; i < ARRAY_SIZE(fb_addr); i++) - if (fb_addr[i].fb_type == fb_type) { - *virt_addr = (void *)(dum_data.lcd_virt_start + - fb_addr[i].addr_offset); - *phys_addr = - dum_data.lcd_phys_start + fb_addr[i].addr_offset; - *fb_length = fb_addr[i].fb_length; - ret = 0; - break; - } - - return ret; -} - -EXPORT_SYMBOL(pnx4008_get_fb_addresses); - -int pnx4008_alloc_dum_channel(int dev_id) -{ - int i = 0; - - while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1)) - i++; - - if (i == MAX_DUM_CHANNELS) - return -ENORESOURCESLEFT; - else { - dum_data.fb_owning_channel[i] = dev_id; - return i; - } -} - -EXPORT_SYMBOL(pnx4008_alloc_dum_channel); - -int pnx4008_free_dum_channel(int channr, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - clear_channel(channr); - dum_data.fb_owning_channel[channr] = -1; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_free_dum_channel); - -int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id) -{ - int i = chan_uf.channelnr; - int ret; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[i] != dev_id) - return -EFBNOTOWNER; - else if ((ret = - display_open(chan_uf.channelnr, 0, chan_uf.dirty, - chan_uf.source, chan_uf.y_offset, - chan_uf.x_offset, chan_uf.height, - chan_uf.width)) != 0) - return ret; - else { - dum_data.chan_uf_store[i].dirty = chan_uf.dirty; - dum_data.chan_uf_store[i].source = chan_uf.source; - dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset; - dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset; - dum_data.chan_uf_store[i].width = chan_uf.width; - dum_data.chan_uf_store[i].height = chan_uf.height; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_put_dum_channel_uf); - -int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - if (val == CONF_SYNC_ON) { - DUM_CH_CONF(channr) |= CONF_SYNCENABLE; - DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK | - DUM_CHANNEL_CFG_SYNC_MASK_SET; - } else if (val == CONF_SYNC_OFF) - DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE; - else - return -EINVAL; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_set_dum_channel_sync); - -int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - if (val == CONF_DIRTYDETECTION_ON) - DUM_CH_CONF(channr) |= CONF_DIRTYENABLE; - else if (val == CONF_DIRTYDETECTION_OFF) - DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE; - else - return -EINVAL; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect); - -#if 0 /* Functions not used currently, but likely to be used in future */ - -static int get_channel(struct dumchannel *p_chan) -{ - int i = p_chan->channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else { - p_chan->dum_ch_min = DUM_CH_MIN(i); - p_chan->dum_ch_max = DUM_CH_MAX(i); - p_chan->dum_ch_conf = DUM_CH_CONF(i); - p_chan->dum_ch_stat = DUM_CH_STAT(i); - p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */ - } - - return 0; -} - -int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id) -{ - int i = p_chan_uf->channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[i] != dev_id) - return -EFBNOTOWNER; - else { - p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty; - p_chan_uf->source = dum_data.chan_uf_store[i].source; - p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset; - p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset; - p_chan_uf->width = dum_data.chan_uf_store[i].width; - p_chan_uf->height = dum_data.chan_uf_store[i].height; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_get_dum_channel_uf); - -int pnx4008_get_dum_channel_config(int channr, int dev_id) -{ - int ret; - struct dumchannel chan; - - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - chan.channelnr = channr; - if ((ret = get_channel(&chan)) != 0) - return ret; - } - - return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK); -} - -EXPORT_SYMBOL(pnx4008_get_dum_channel_config); - -int pnx4008_force_update_dum_channel(int channr, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else - DUM_CH_CTRL(channr) = CTRL_SETDIRTY; - - return 0; -} - -EXPORT_SYMBOL(pnx4008_force_update_dum_channel); - -#endif - -int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, - struct device *dev) -{ - unsigned long off = vma->vm_pgoff << PAGE_SHIFT; - - if (off < info->fix.smem_len) { - vma->vm_pgoff += 1; - return dma_mmap_writecombine(dev, vma, - (void *)dum_data.lcd_virt_start, - dum_data.lcd_phys_start, - FB_DMA_SIZE); - } - return -EINVAL; -} - -EXPORT_SYMBOL(pnx4008_sdum_mmap); - -int pnx4008_set_dum_exit_notification(int dev_id) -{ - int i; - - for (i = 0; i < MAX_DUM_CHANNELS; i++) - if (dum_data.fb_owning_channel[i] == dev_id) - return -ERESOURCESNOTFREED; - - return 0; -} - -EXPORT_SYMBOL(pnx4008_set_dum_exit_notification); - -/* Platform device driver for DUM */ - -static int sdum_suspend(struct platform_device *pdev, pm_message_t state) -{ - int retval = 0; - struct clk *clk; - - clk = clk_get(0, "dum_ck"); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 0); - clk_put(clk); - } else - retval = PTR_ERR(clk); - - /* disable BAC */ - DUM_CTRL = V_BAC_DISABLE_IDLE; - - /* LCD standby & turn off display */ - lcd_reset(); - - return retval; -} - -static int sdum_resume(struct platform_device *pdev) -{ - int retval = 0; - struct clk *clk; - - clk = clk_get(0, "dum_ck"); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 1); - clk_put(clk); - } else - retval = PTR_ERR(clk); - - /* wait for BAC disable */ - DUM_CTRL = V_BAC_DISABLE_TRIG; - - while (DUM_CTRL & BAC_ENABLED) - udelay(10); - - /* re-init LCD */ - lcd_init(); - - /* enable BAC and reset MUX */ - DUM_CTRL = V_BAC_ENABLE; - udelay(1); - DUM_CTRL = V_MUX_RESET; - return 0; -} - -static int __devinit sdum_probe(struct platform_device *pdev) -{ - int ret = 0, i = 0; - - /* map frame buffer */ - dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev, - FB_DMA_SIZE, - &dum_data.lcd_phys_start, - GFP_KERNEL); - - if (!dum_data.lcd_virt_start) { - ret = -ENOMEM; - goto out_3; - } - - /* map slave registers */ - dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE; - dum_data.slave_virt_base = - (u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32)); - - if (dum_data.slave_virt_base == NULL) { - ret = -ENOMEM; - goto out_2; - } - - /* initialize DUM and LCD display */ - ret = dum_init(pdev); - if (ret) - goto out_1; - - dum_chan_init(); - lcd_init(); - - DUM_CTRL = V_BAC_ENABLE; - udelay(1); - DUM_CTRL = V_MUX_RESET; - - /* set decode address and sync clock divider */ - DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK; - DUM_CLK_DIV = PNX4008_DUM_CLK_DIV; - - for (i = 0; i < MAX_DUM_CHANNELS; i++) - dum_data.fb_owning_channel[i] = -1; - - /*setup wakeup interrupt */ - start_int_set_rising_edge(SE_DISP_SYNC_INT); - start_int_ack(SE_DISP_SYNC_INT); - start_int_umask(SE_DISP_SYNC_INT); - - return 0; - -out_1: - iounmap((void *)dum_data.slave_virt_base); -out_2: - dma_free_writecombine(&pdev->dev, FB_DMA_SIZE, - (void *)dum_data.lcd_virt_start, - dum_data.lcd_phys_start); -out_3: - return ret; -} - -static int sdum_remove(struct platform_device *pdev) -{ - struct clk *clk; - - start_int_mask(SE_DISP_SYNC_INT); - - clk = clk_get(0, "dum_ck"); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 0); - clk_put(clk); - } - - iounmap((void *)dum_data.slave_virt_base); - - dma_free_writecombine(&pdev->dev, FB_DMA_SIZE, - (void *)dum_data.lcd_virt_start, - dum_data.lcd_phys_start); - - return 0; -} - -static struct platform_driver sdum_driver = { - .driver = { - .name = "pnx4008-sdum", - }, - .probe = sdum_probe, - .remove = sdum_remove, - .suspend = sdum_suspend, - .resume = sdum_resume, -}; - -module_platform_driver(sdum_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h deleted file mode 100644 index 189c3d641383..000000000000 --- a/drivers/video/pnx4008/sdum.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2005 Philips Semiconductors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html -*/ - -#define MAX_DUM_CHANNELS 64 - -#define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000) - -#define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1) -#define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1) - -#define CTRL_SETDIRTY (0x00000001) -#define CONF_DIRTYENABLE (0x00000020) -#define CONF_SYNCENABLE (0x00000004) - -#define DIRTY_ENABLED(conf) ((conf) & 0x0020) -#define SYNC_ENABLED(conf) ((conf) & 0x0004) - -/* Display 1 & 2 Write Timing Configuration */ -#define PNX4008_DUM_WT_CFG 0x00372000 - -/* Display 1 & 2 Read Timing Configuration */ -#define PNX4008_DUM_RT_CFG 0x00003A47 - -/* DUM Transit State Timing Configuration */ -#define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */ - -/* DUM Sync count clock divider */ -#define PNX4008_DUM_CLK_DIV 0x02DD - -/* Memory size for framebuffer, allocated through dma_alloc_writecombine(). - * Must be PAGE aligned - */ -#define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE)) - -#define OFFSET_RGBBUFFER (0xB0000) -#define OFFSET_YUVBUFFER (0x00000) - -#define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER) -#define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER) - -#define CMDSTRING_BASEADDR (0x00C000) /* iram */ -#define BYTES_PER_CMDSTRING (0x80) -#define NR_OF_CMDSTRINGS (64) - -#define MAX_NR_PRESTRINGS (0x40) -#define MAX_NR_POSTSTRINGS (0x40) - -/* various mask definitions */ -#define DUM_CLK_ENABLE 0x01 -#define DUM_CLK_DISABLE 0 -#define DUM_DECODE_MASK 0x1FFFFFFF -#define DUM_CHANNEL_CFG_MASK 0x01FF -#define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF -#define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00 - -#define SDUM_RETURNVAL_BASE (0x500) - -#define CONF_SYNC_OFF (0x602) -#define CONF_SYNC_ON (0x603) - -#define CONF_DIRTYDETECTION_OFF (0x600) -#define CONF_DIRTYDETECTION_ON (0x601) - -struct dumchannel_uf { - int channelnr; - u32 *dirty; - u32 *source; - u32 x_offset; - u32 y_offset; - u32 width; - u32 height; -}; - -enum { - FB_TYPE_YUV, - FB_TYPE_RGB -}; - -struct cmdstring { - int channelnr; - uint16_t prestringlen; - uint16_t poststringlen; - uint16_t format; - uint16_t reserved; - uint16_t startaddr_low; - uint16_t startaddr_high; - uint16_t pixdatlen_low; - uint16_t pixdatlen_high; - u32 precmd[MAX_NR_PRESTRINGS]; - u32 postcmd[MAX_NR_POSTSTRINGS]; - -}; - -struct dumchannel { - int channelnr; - int dum_ch_min; - int dum_ch_max; - int dum_ch_conf; - int dum_ch_stat; - int dum_ch_ctrl; -}; - -int pnx4008_alloc_dum_channel(int dev_id); -int pnx4008_free_dum_channel(int channr, int dev_id); - -int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id); -int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id); - -int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id); -int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id); - -int pnx4008_force_dum_update_channel(int channr, int dev_id); - -int pnx4008_get_dum_channel_config(int channr, int dev_id); - -int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev); -int pnx4008_set_dum_exit_notification(int dev_id); - -int pnx4008_get_fb_addresses(int fb_type, void **virt_addr, - dma_addr_t * phys_addr, int *fb_length); diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 4e292f29bf5d..0b340d6ff8a4 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -1034,6 +1034,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); + retval = -ENOMEM; goto err_close_device; } dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); @@ -1046,6 +1047,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dev_err(&dev->core, "%s: lv1_gpu_context_allocate failed: %d\n", __func__, status); + retval = -ENOMEM; goto err_gpu_memory_free; } @@ -1053,6 +1055,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); if (!dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); + retval = -ENOMEM; goto err_gpu_context_free; } @@ -1121,8 +1124,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); - if (!info) + if (!info) { + retval = -ENOMEM; goto err_context_fb_close; + } par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 69bf9d07c237..2ed7b633bbd9 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -25,8 +25,8 @@ #include <linux/interrupt.h> #include <linux/pm_runtime.h> +#include <video/samsung_fimd.h> #include <mach/map.h> -#include <plat/regs-fb-v4.h> #include <plat/fb.h> /* This driver will export a number of framebuffer interfaces depending @@ -1398,35 +1398,28 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) spin_lock_init(&sfb->slock); - sfb->bus_clk = clk_get(dev, "lcd"); + sfb->bus_clk = devm_clk_get(dev, "lcd"); if (IS_ERR(sfb->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); - ret = PTR_ERR(sfb->bus_clk); - goto err_sfb; + return PTR_ERR(sfb->bus_clk); } - clk_enable(sfb->bus_clk); + clk_prepare_enable(sfb->bus_clk); if (!sfb->variant.has_clksel) { - sfb->lcd_clk = clk_get(dev, "sclk_fimd"); + sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd"); if (IS_ERR(sfb->lcd_clk)) { dev_err(dev, "failed to get lcd clock\n"); ret = PTR_ERR(sfb->lcd_clk); goto err_bus_clk; } - clk_enable(sfb->lcd_clk); + clk_prepare_enable(sfb->lcd_clk); } pm_runtime_enable(sfb->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to find registers\n"); - ret = -ENOENT; - goto err_lcd_clk; - } - sfb->regs = devm_request_and_ioremap(dev, res); if (!sfb->regs) { dev_err(dev, "failed to map registers\n"); @@ -1510,16 +1503,12 @@ err_pm_runtime: err_lcd_clk: pm_runtime_disable(sfb->dev); - if (!sfb->variant.has_clksel) { - clk_disable(sfb->lcd_clk); - clk_put(sfb->lcd_clk); - } + if (!sfb->variant.has_clksel) + clk_disable_unprepare(sfb->lcd_clk); err_bus_clk: - clk_disable(sfb->bus_clk); - clk_put(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); -err_sfb: return ret; } @@ -1541,13 +1530,10 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) if (sfb->windows[win]) s3c_fb_release_win(sfb, sfb->windows[win]); - if (!sfb->variant.has_clksel) { - clk_disable(sfb->lcd_clk); - clk_put(sfb->lcd_clk); - } + if (!sfb->variant.has_clksel) + clk_disable_unprepare(sfb->lcd_clk); - clk_disable(sfb->bus_clk); - clk_put(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); pm_runtime_put_sync(sfb->dev); pm_runtime_disable(sfb->dev); @@ -1575,9 +1561,9 @@ static int s3c_fb_suspend(struct device *dev) } if (!sfb->variant.has_clksel) - clk_disable(sfb->lcd_clk); + clk_disable_unprepare(sfb->lcd_clk); - clk_disable(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); pm_runtime_put_sync(sfb->dev); @@ -1595,10 +1581,10 @@ static int s3c_fb_resume(struct device *dev) pm_runtime_get_sync(sfb->dev); - clk_enable(sfb->bus_clk); + clk_prepare_enable(sfb->bus_clk); if (!sfb->variant.has_clksel) - clk_enable(sfb->lcd_clk); + clk_prepare_enable(sfb->lcd_clk); /* setup gpio and output polarity controls */ pd->setup_gpio(); @@ -1654,9 +1640,9 @@ static int s3c_fb_runtime_suspend(struct device *dev) struct s3c_fb *sfb = platform_get_drvdata(pdev); if (!sfb->variant.has_clksel) - clk_disable(sfb->lcd_clk); + clk_disable_unprepare(sfb->lcd_clk); - clk_disable(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); return 0; } @@ -1667,10 +1653,10 @@ static int s3c_fb_runtime_resume(struct device *dev) struct s3c_fb *sfb = platform_get_drvdata(pdev); struct s3c_fb_platdata *pd = sfb->pdata; - clk_enable(sfb->bus_clk); + clk_prepare_enable(sfb->bus_clk); if (!sfb->variant.has_clksel) - clk_enable(sfb->lcd_clk); + clk_prepare_enable(sfb->lcd_clk); /* setup gpio and output polarity controls */ pd->setup_gpio(); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 77f34c614c86..1083bb9469ee 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -11,6 +11,8 @@ * Driver based on skeletonfb.c, sa1100fb.c and others. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/err.h> @@ -48,7 +50,11 @@ static int debug = 1; static int debug; #endif -#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg); +#define dprintk(msg...) \ +do { \ + if (debug) \ + pr_debug(msg); \ +} while (0) /* useful functions */ @@ -598,11 +604,11 @@ static int s3c2410fb_debug_store(struct device *dev, if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0) { debug = 1; - printk(KERN_DEBUG "s3c2410fb: Debug On"); + dev_dbg(dev, "s3c2410fb: Debug On"); } else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0) { debug = 0; - printk(KERN_DEBUG "s3c2410fb: Debug Off"); + dev_dbg(dev, "s3c2410fb: Debug Off"); } else { return -EINVAL; } @@ -921,7 +927,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, info->clk = clk_get(NULL, "lcd"); if (IS_ERR(info->clk)) { - printk(KERN_ERR "failed to get lcd clock source\n"); + dev_err(&pdev->dev, "failed to get lcd clock source\n"); ret = PTR_ERR(info->clk); goto release_irq; } @@ -929,7 +935,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, clk_enable(info->clk); dprintk("got and enabled clock\n"); - usleep_range(1000, 1000); + usleep_range(1000, 1100); info->clk_rate = clk_get_rate(info->clk); @@ -947,7 +953,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, /* Initialize video memory */ ret = s3c2410fb_map_video_memory(fbinfo); if (ret) { - printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret); + dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto release_clock; } @@ -970,7 +976,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, ret = register_framebuffer(fbinfo); if (ret < 0) { - printk(KERN_ERR "Failed to register framebuffer device: %d\n", + dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n", ret); goto free_cpufreq; } @@ -978,9 +984,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, /* create device files */ ret = device_create_file(&pdev->dev, &dev_attr_debug); if (ret) - printk(KERN_ERR "failed to add debug attribute\n"); + dev_err(&pdev->dev, "failed to add debug attribute\n"); - printk(KERN_INFO "fb%d: %s frame buffer device\n", + dev_info(&pdev->dev, "fb%d: %s frame buffer device\n", fbinfo->node, fbinfo->fix.id); return 0; @@ -1028,7 +1034,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev) s3c2410fb_cpufreq_deregister(info); s3c2410fb_lcd_enable(info, 0); - usleep_range(1000, 1000); + usleep_range(1000, 1100); s3c2410fb_unmap_video_memory(fbinfo); @@ -1065,7 +1071,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) * the LCD DMA engine is not going to get back on the bus * before the clock goes off again (bjd) */ - usleep_range(1000, 1000); + usleep_range(1000, 1100); clk_disable(info->clk); return 0; @@ -1077,7 +1083,7 @@ static int s3c2410fb_resume(struct platform_device *dev) struct s3c2410fb_info *info = fbinfo->par; clk_enable(info->clk); - usleep_range(1000, 1000); + usleep_range(1000, 1100); s3c2410fb_init_registers(fbinfo); @@ -1134,8 +1140,8 @@ static void __exit s3c2410fb_cleanup(void) module_init(s3c2410fb_init); module_exit(s3c2410fb_cleanup); -MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " - "Ben Dooks <ben-linux@fluff.org>"); +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); +MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s3c2410-lcd"); diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 0d0f52c18fd8..f4f53b082d05 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -2266,8 +2266,10 @@ static int __devinit savagefb_probe(struct pci_dev* dev, lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3); info->var.yres_virtual = info->fix.smem_len/lpitch; - if (info->var.yres_virtual < info->var.yres) + if (info->var.yres_virtual < info->var.yres) { + err = -ENOMEM; goto failed; + } #if defined(CONFIG_FB_SAVAGE_ACCEL) /* diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c index 9dec64da4015..3ab18f5a3759 100644 --- a/drivers/video/sis/initextlfb.c +++ b/drivers/video/sis/initextlfb.c @@ -65,7 +65,7 @@ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, } #endif - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) { printk(KERN_ERR "Could not find mode %x\n", ModeNo); return 65000; } diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c index b7f27acaf817..729a50722bdf 100644 --- a/drivers/video/sunxvr1000.c +++ b/drivers/video/sunxvr1000.c @@ -141,8 +141,10 @@ static int __devinit gfb_probe(struct platform_device *op) gp->fb_base = of_ioremap(&op->resource[6], 0, gp->fb_size, "gfb fb"); - if (!gp->fb_base) + if (!gp->fb_base) { + err = -ENOMEM; goto err_release_fb; + } err = gfb_set_fbinfo(gp); if (err) diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c index 5848436c19da..7fbcba86d1a2 100644 --- a/drivers/video/sunxvr2500.c +++ b/drivers/video/sunxvr2500.c @@ -181,8 +181,10 @@ static int __devinit s3d_pci_register(struct pci_dev *pdev, sp->fb_size = info->fix.line_length * sp->height; sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size); - if (!sp->fb_base) + if (!sp->fb_base) { + err = -ENOMEM; goto err_release_pci; + } err = s3d_set_fbinfo(sp); if (err) diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c index eb931b8626fa..6c71b1b44477 100644 --- a/drivers/video/sunxvr500.c +++ b/drivers/video/sunxvr500.c @@ -298,8 +298,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev, goto err_release_fb; } ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000); - if (!ep->ramdac) + if (!ep->ramdac) { + err = -ENOMEM; goto err_release_pci1; + } ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0); ep->fb8_0_off -= ep->fb_base_reg; @@ -343,8 +345,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev, ep->fb_size = info->fix.line_length * ep->height; ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size); - if (!ep->fb_base) + if (!ep->fb_base) { + err = -ENOMEM; goto err_release_pci0; + } err = e3d_set_fbinfo(ep); if (err) diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index f45eba3d6150..86d449ea3169 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -646,7 +646,7 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf, result = fb_sys_write(info, buf, count, ppos); if (result > 0) { - int start = max((int)(offset / info->fix.line_length) - 1, 0); + int start = max((int)(offset / info->fix.line_length), 0); int lines = min((u32)((result / info->fix.line_length) + 1), (u32)info->var.yres); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index b0e2a4261afe..2f8f82d874a1 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -659,6 +659,8 @@ static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task, task->t.flags = TF_BUF_RET | TF_BUF_ESDI; task->t.buf_len = EDID_LENGTH; task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL); + if (!task->buf) + return -ENOMEM; err = uvesafb_exec(task); diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 89aef343e295..4709edc3cb7f 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -1167,8 +1167,7 @@ void vmlfb_unregister_subsys(struct vml_sys *sys) list_for_each_entry_safe(entry, next, &global_has_mode, head) { printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n"); vmlfb_disable_pipe(entry); - list_del(&entry->head); - list_add_tail(&entry->head, &global_no_mode); + list_move_tail(&entry->head, &global_no_mode); } mutex_unlock(&vml_mutex); } diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c index af8f26b643c1..db1e39277e32 100644 --- a/drivers/video/via/via_clock.c +++ b/drivers/video/via/via_clock.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/via-core.h> +#include <asm/olpc.h> #include "via_clock.h" #include "global.h" #include "debug.h" @@ -289,6 +290,10 @@ static void dummy_set_pll(struct via_pll_config config) printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap); } +static void noop_set_clock_state(u8 state) +{ +} + void via_clock_init(struct via_clock *clock, int gfx_chip) { switch (gfx_chip) { @@ -346,4 +351,18 @@ void via_clock_init(struct via_clock *clock, int gfx_chip) break; } + + if (machine_is_olpc()) { + /* The OLPC XO-1.5 cannot suspend/resume reliably if the + * IGA1/IGA2 clocks are set as on or off (memory rot + * occasionally happens during suspend under such + * configurations). + * + * The only known stable scenario is to leave this bits as-is, + * which in their default states are documented to enable the + * clock only when it is needed. + */ + clock->set_primary_clock_state = noop_set_clock_state; + clock->set_secondary_clock_state = noop_set_clock_state; + } } diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 131dec04794e..48220e129f85 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -48,6 +48,7 @@ #include <xen/xenbus.h> #include <xen/xen.h> #include "xenbus_comms.h" +#include <asm/xen/hypervisor.h> struct xs_stored_msg { struct list_head list; @@ -618,7 +619,24 @@ static struct xenbus_watch *find_watch(const char *token) return NULL; } +/* + * Certain older XenBus toolstack cannot handle reading values that are + * not populated. Some Xen 3.4 installation are incapable of doing this + * so if we are running on anything older than 4 do not attempt to read + * control/platform-feature-xs_reset_watches. + */ +static bool xen_strict_xenbus_quirk() +{ + uint32_t eax, ebx, ecx, edx, base; + + base = xen_cpuid_base(); + cpuid(base + 1, &eax, &ebx, &ecx, &edx); + if ((eax >> 16) < 4) + return true; + return false; + +} static void xs_reset_watches(void) { int err, supported = 0; @@ -626,6 +644,9 @@ static void xs_reset_watches(void) if (!xen_hvm_domain() || xen_initial_domain()) return; + if (xen_strict_xenbus_quirk()) + return; + err = xenbus_scanf(XBT_NIL, "control", "platform-feature-xs_reset_watches", "%d", &supported); if (err != 1 || !supported) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 392c5dac1981..d934f04e7736 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -184,10 +184,20 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) v9ses->afid = option; break; case Opt_uname: - match_strlcpy(v9ses->uname, &args[0], PATH_MAX); + kfree(v9ses->uname); + v9ses->uname = match_strdup(&args[0]); + if (!v9ses->uname) { + ret = -ENOMEM; + goto free_and_return; + } break; case Opt_remotename: - match_strlcpy(v9ses->aname, &args[0], PATH_MAX); + kfree(v9ses->aname); + v9ses->aname = match_strdup(&args[0]); + if (!v9ses->aname) { + ret = -ENOMEM; + goto free_and_return; + } break; case Opt_nodevmap: v9ses->nodev = 1; @@ -287,21 +297,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, struct p9_fid *fid; int rc; - v9ses->uname = __getname(); + v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL); if (!v9ses->uname) return ERR_PTR(-ENOMEM); - v9ses->aname = __getname(); + v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL); if (!v9ses->aname) { - __putname(v9ses->uname); + kfree(v9ses->uname); return ERR_PTR(-ENOMEM); } init_rwsem(&v9ses->rename_sem); rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY); if (rc) { - __putname(v9ses->aname); - __putname(v9ses->uname); + kfree(v9ses->aname); + kfree(v9ses->uname); return ERR_PTR(rc); } @@ -309,8 +319,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, list_add(&v9ses->slist, &v9fs_sessionlist); spin_unlock(&v9fs_sessionlist_lock); - strcpy(v9ses->uname, V9FS_DEFUSER); - strcpy(v9ses->aname, V9FS_DEFANAME); v9ses->uid = ~0; v9ses->dfltuid = V9FS_DEFUID; v9ses->dfltgid = V9FS_DEFGID; @@ -412,8 +420,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) kfree(v9ses->cachetag); } #endif - __putname(v9ses->uname); - __putname(v9ses->aname); + kfree(v9ses->uname); + kfree(v9ses->aname); bdi_destroy(&v9ses->bdi); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index cbf9dbb1b2a2..890bed538f9b 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1276,12 +1276,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) } /* copy extension buffer into buffer */ - strncpy(buffer, st->extension, buflen); + retval = min(strlen(st->extension)+1, (size_t)buflen); + memcpy(buffer, st->extension, retval); - p9_debug(P9_DEBUG_VFS, "%s -> %s (%s)\n", - dentry->d_name.name, st->extension, buffer); + p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n", + dentry->d_name.name, st->extension, buflen, buffer); - retval = strnlen(buffer, buflen); done: p9stat_free(st); kfree(st); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index e7396cfdb109..91b11650722e 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -392,10 +392,12 @@ static struct vfsmount *autofs4_d_automount(struct path *path) ino->flags |= AUTOFS_INF_PENDING; spin_unlock(&sbi->fs_lock); status = autofs4_mount_wait(dentry); - if (status) - return ERR_PTR(status); spin_lock(&sbi->fs_lock); ino->flags &= ~AUTOFS_INF_PENDING; + if (status) { + spin_unlock(&sbi->fs_lock); + return ERR_PTR(status); + } } done: if (!(ino->flags & AUTOFS_INF_EXPIRING)) { diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index e568c472f807..61168805f175 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -638,7 +638,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir) return -ENOENT; BUG_ON(victim->d_parent->d_inode != dir); - audit_inode_child(victim, dir); + audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); error = inode_permission(dir, MAY_WRITE | MAY_EXEC); if (error) diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 8e1b60e557b6..02ce90972d81 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -99,7 +99,7 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len, * FIXME: we should try harder by querying the mds for the ino. */ static struct dentry *__fh_to_dentry(struct super_block *sb, - struct ceph_nfs_fh *fh) + struct ceph_nfs_fh *fh, int fh_len) { struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; struct inode *inode; @@ -107,6 +107,9 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, struct ceph_vino vino; int err; + if (fh_len < sizeof(*fh) / 4) + return ERR_PTR(-ESTALE); + dout("__fh_to_dentry %llx\n", fh->ino); vino.ino = fh->ino; vino.snap = CEPH_NOSNAP; @@ -150,7 +153,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, * convert connectable fh to dentry */ static struct dentry *__cfh_to_dentry(struct super_block *sb, - struct ceph_nfs_confh *cfh) + struct ceph_nfs_confh *cfh, int fh_len) { struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; struct inode *inode; @@ -158,6 +161,9 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb, struct ceph_vino vino; int err; + if (fh_len < sizeof(*cfh) / 4) + return ERR_PTR(-ESTALE); + dout("__cfh_to_dentry %llx (%llx/%x)\n", cfh->ino, cfh->parent_ino, cfh->parent_name_hash); @@ -207,9 +213,11 @@ static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { if (fh_type == 1) - return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw); + return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw, + fh_len); else - return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw); + return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw, + fh_len); } /* @@ -230,6 +238,8 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, if (fh_type == 1) return ERR_PTR(-ESTALE); + if (fh_len < sizeof(*cfh) / 4) + return ERR_PTR(-ESTALE); pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino, cfh->parent_name_hash); diff --git a/fs/compat.c b/fs/compat.c index b7a24d0ca30d..015e1e1f87c6 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -776,16 +776,16 @@ asmlinkage long compat_sys_mount(const char __user * dev_name, char *kernel_type; unsigned long data_page; char *kernel_dev; - char *dir_page; + struct filename *dir; int retval; retval = copy_mount_string(type, &kernel_type); if (retval < 0) goto out; - dir_page = getname(dir_name); - retval = PTR_ERR(dir_page); - if (IS_ERR(dir_page)) + dir = getname(dir_name); + retval = PTR_ERR(dir); + if (IS_ERR(dir)) goto out1; retval = copy_mount_string(dev_name, &kernel_dev); @@ -807,7 +807,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name, } } - retval = do_mount(kernel_dev, dir_page, kernel_type, + retval = do_mount(kernel_dev, dir->name, kernel_type, flags, (void*)data_page); out4: @@ -815,7 +815,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name, out3: kfree(kernel_dev); out2: - putname(dir_page); + putname(dir); out1: kfree(kernel_type); out: diff --git a/fs/exec.c b/fs/exec.c index ca434534ae9a..8b9011b67041 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -105,7 +105,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt) SYSCALL_DEFINE1(uselib, const char __user *, library) { struct file *file; - char *tmp = getname(library); + struct filename *tmp = getname(library); int error = PTR_ERR(tmp); static const struct open_flags uselib_flags = { .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, @@ -751,13 +751,14 @@ struct file *open_exec(const char *name) { struct file *file; int err; + struct filename tmp = { .name = name }; static const struct open_flags open_exec_flags = { .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, .acc_mode = MAY_EXEC | MAY_OPEN, .intent = LOOKUP_OPEN }; - file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW); + file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW); if (IS_ERR(file)) goto out; @@ -1664,10 +1665,10 @@ SYSCALL_DEFINE3(execve, const char __user *const __user *, argv, const char __user *const __user *, envp) { - const char *path = getname(filename); + struct filename *path = getname(filename); int error = PTR_ERR(path); if (!IS_ERR(path)) { - error = do_execve(path, argv, envp, current_pt_regs()); + error = do_execve(path->name, argv, envp, current_pt_regs()); putname(path); } return error; @@ -1677,10 +1678,11 @@ asmlinkage long compat_sys_execve(const char __user * filename, const compat_uptr_t __user * argv, const compat_uptr_t __user * envp) { - const char *path = getname(filename); + struct filename *path = getname(filename); int error = PTR_ERR(path); if (!IS_ERR(path)) { - error = compat_do_execve(path, argv, envp, current_pt_regs()); + error = compat_do_execve(path->name, argv, envp, + current_pt_regs()); putname(path); } return error; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 59e3bbfac0b1..5e59280d42d7 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -389,8 +389,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait) if (unlikely(ret)) goto out; - lock_super(sb); - ios->length = offsetof(struct exofs_fscb, s_dev_table_oid); memset(fscb, 0, ios->length); fscb->s_nextid = cpu_to_le64(sbi->s_nextid); @@ -406,8 +404,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait) if (unlikely(ret)) EXOFS_ERR("%s: ore_write failed.\n", __func__); - - unlock_super(sb); out: EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret); ore_put_io_state(ios); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 17ae5c83d234..29e79713c7eb 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2578,11 +2578,9 @@ out: static int ext3_unfreeze(struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) { - lock_super(sb); /* Reser the needs_recovery flag before the fs is unlocked. */ EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); - unlock_super(sb); journal_unlock_updates(EXT3_SB(sb)->s_journal); } return 0; @@ -2602,7 +2600,6 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) #endif /* Store the original options */ - lock_super(sb); old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; old_opts.s_resuid = sbi->s_resuid; @@ -2708,8 +2705,6 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) old_opts.s_qf_names[i] != sbi->s_qf_names[i]) kfree(old_opts.s_qf_names[i]); #endif - unlock_super(sb); - if (enable_quota) dquot_resume(sb, -1); return 0; @@ -2728,7 +2723,6 @@ restore_opts: sbi->s_qf_names[i] = old_opts.s_qf_names[i]; } #endif - unlock_super(sb); return err; } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index bca6d0a1255e..2a182342442e 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -571,7 +571,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, int short_len = 0, fill_len = 0; int ret = 0; - lock_super(sb); + mutex_lock(&sbi->s_lock); cpos = filp->f_pos; /* Fake . and .. for the root directory. */ @@ -693,7 +693,7 @@ fill_failed: if (unicode) __putname(unicode); out: - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return ret; } diff --git a/fs/fat/fat.h b/fs/fat/fat.h index ca7e8f8bad7c..623f36f0423b 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -71,8 +71,9 @@ struct msdos_sb_info { unsigned long root_cluster; /* first cluster of the root directory */ unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ struct mutex fat_lock; - unsigned int prev_free; /* previously allocated cluster number */ - unsigned int free_clusters; /* -1 if undefined */ + struct mutex s_lock; + unsigned int prev_free; /* previously allocated cluster number */ + unsigned int free_clusters; /* -1 if undefined */ unsigned int free_clus_valid; /* is free_clusters valid? */ struct fat_mount_options options; struct nls_table *nls_disk; /* Codepage used on disk */ diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 76f60c642c06..5bafaad00530 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -673,9 +673,9 @@ static int fat_write_inode(struct inode *inode, struct writeback_control *wbc) if (inode->i_ino == MSDOS_FSINFO_INO) { struct super_block *sb = inode->i_sb; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = fat_clusters_flush(sb); - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); } else err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); @@ -1268,6 +1268,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, b = (struct fat_boot_sector *) bh->b_data; } + mutex_init(&sbi->s_lock); sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus; sbi->cluster_bits = ffs(sbi->cluster_size) - 1; sbi->fats = b->fats; diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index c1055e778fff..e2cfda94a28d 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -208,7 +208,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); switch (err) { case -ENOENT: @@ -221,7 +221,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, default: inode = ERR_PTR(err); } - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return d_splice_alias(inode, dentry); } @@ -273,7 +273,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode, unsigned char msdos_name[MSDOS_NAME]; int err, is_hid; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = msdos_format_name(dentry->d_name.name, dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); @@ -302,7 +302,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode, d_instantiate(dentry, inode); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); if (!err) err = fat_flush_inodes(sb, dir, inode); return err; @@ -316,7 +316,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) struct fat_slot_info sinfo; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); /* * Check whether the directory is not in use, then check * whether it is empty. @@ -337,7 +337,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) inode->i_ctime = CURRENT_TIME_SEC; fat_detach(inode); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); if (!err) err = fat_flush_inodes(sb, dir, inode); @@ -354,7 +354,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct timespec ts; int err, is_hid, cluster; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = msdos_format_name(dentry->d_name.name, dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); @@ -392,14 +392,14 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) d_instantiate(dentry, inode); - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); fat_flush_inodes(sb, dir, inode); return 0; out_free: fat_free_clusters(dir, cluster); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return err; } @@ -411,7 +411,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) struct fat_slot_info sinfo; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); if (err) goto out; @@ -423,7 +423,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) inode->i_ctime = CURRENT_TIME_SEC; fat_detach(inode); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); if (!err) err = fat_flush_inodes(sb, dir, inode); @@ -606,7 +606,7 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME]; int err, is_hid; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = msdos_format_name(old_dentry->d_name.name, old_dentry->d_name.len, old_msdos_name, @@ -625,7 +625,7 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, err = do_msdos_rename(old_dir, old_msdos_name, old_dentry, new_dir, new_msdos_name, new_dentry, is_hid); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); if (!err) err = fat_flush_inodes(sb, old_dir, new_dir); return err; diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index e535dd75b986..ac959d655e7d 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -721,7 +721,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, struct dentry *alias; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = vfat_find(dir, &dentry->d_name, &sinfo); if (err) { @@ -752,13 +752,13 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, if (!S_ISDIR(inode->i_mode)) d_move(alias, dentry); iput(inode); - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return alias; } else dput(alias); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); dentry->d_time = dentry->d_parent->d_inode->i_version; dentry = d_splice_alias(inode, dentry); if (dentry) @@ -766,7 +766,7 @@ out: return dentry; error: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return ERR_PTR(err); } @@ -779,7 +779,7 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct timespec ts; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); ts = CURRENT_TIME_SEC; err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo); @@ -800,7 +800,7 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry, inode); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return err; } @@ -811,7 +811,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) struct fat_slot_info sinfo; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = fat_dir_empty(inode); if (err) @@ -829,7 +829,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; fat_detach(inode); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return err; } @@ -841,7 +841,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) struct fat_slot_info sinfo; int err; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = vfat_find(dir, &dentry->d_name, &sinfo); if (err) @@ -854,7 +854,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; fat_detach(inode); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return err; } @@ -867,7 +867,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct timespec ts; int err, cluster; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); ts = CURRENT_TIME_SEC; cluster = fat_alloc_new_dir(dir, &ts); @@ -896,13 +896,13 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry, inode); - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return 0; out_free: fat_free_clusters(dir, cluster); out: - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return err; } @@ -921,7 +921,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; - lock_super(sb); + mutex_lock(&MSDOS_SB(sb)->s_lock); err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo); if (err) goto out; @@ -996,7 +996,7 @@ out: brelse(sinfo.bh); brelse(dotdot_bh); brelse(old_sinfo.bh); - unlock_super(sb); + mutex_unlock(&MSDOS_SB(sb)->s_lock); return err; diff --git a/fs/file.c b/fs/file.c index 0f1bda4bebfa..d3b5fa80b71b 100644 --- a/fs/file.c +++ b/fs/file.c @@ -922,6 +922,9 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) if ((flags & ~O_CLOEXEC) != 0) return -EINVAL; + if (unlikely(oldfd == newfd)) + return -EINVAL; + if (newfd >= rlimit(RLIMIT_NOFILE)) return -EMFILE; diff --git a/fs/file_table.c b/fs/file_table.c index dac67923330f..a72bf9ddd0d2 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -36,7 +36,7 @@ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -DEFINE_LGLOCK(files_lglock); +DEFINE_STATIC_LGLOCK(files_lglock); /* SLAB cache for file structures */ static struct kmem_cache *filp_cachep __read_mostly; diff --git a/fs/filesystems.c b/fs/filesystems.c index 96f24286667a..da165f6adcbf 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_filesystem); static int fs_index(const char __user * __name) { struct file_system_type * tmp; - char * name; + struct filename *name; int err, index; name = getname(__name); @@ -135,7 +135,7 @@ static int fs_index(const char __user * __name) err = -EINVAL; read_lock(&file_systems_lock); for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { - if (strcmp(tmp->name,name) == 0) { + if (strcmp(tmp->name, name->name) == 0) { err = index; break; } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 401b6c6248ae..51ea267d444c 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -249,7 +249,7 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t) } /* - * Move expired (dirtied after work->older_than_this) dirty inodes from + * Move expired (dirtied before work->older_than_this) dirty inodes from * @delaying_queue to @dispatch_queue. */ static int move_expired_inodes(struct list_head *delaying_queue, diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index e8ed6d4a6181..4767774a5f3e 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -161,6 +161,8 @@ static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid, case GFS2_SMALL_FH_SIZE: case GFS2_LARGE_FH_SIZE: case GFS2_OLD_FH_SIZE: + if (fh_len < GFS2_SMALL_FH_SIZE) + return NULL; this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32; this.no_formal_ino |= be32_to_cpu(fh[1]); this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32; @@ -180,6 +182,8 @@ static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid, switch (fh_type) { case GFS2_LARGE_FH_SIZE: case GFS2_OLD_FH_SIZE: + if (fh_len < GFS2_LARGE_FH_SIZE) + return NULL; parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32; parent.no_formal_ino |= be32_to_cpu(fh[5]); parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index bc28bf077a6a..a3076228523d 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -398,7 +398,6 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) *flags |= MS_NOATIME; hpfs_lock(s); - lock_super(s); uid = sbi->sb_uid; gid = sbi->sb_gid; umask = 0777 & ~sbi->sb_mode; lowercase = sbi->sb_lowercase; @@ -431,12 +430,10 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) replace_mount_options(s, new_opts); - unlock_super(s); hpfs_unlock(s); return 0; out_err: - unlock_super(s); hpfs_unlock(s); kfree(new_opts); return -EINVAL; diff --git a/fs/internal.h b/fs/internal.h index 371bcc4b1697..916b7cbf3e3e 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -97,8 +97,8 @@ struct open_flags { int acc_mode; int intent; }; -extern struct file *do_filp_open(int dfd, const char *pathname, - const struct open_flags *op, int lookup_flags); +extern struct file *do_filp_open(int dfd, struct filename *pathname, + const struct open_flags *op, int flags); extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, const char *, const struct open_flags *, int lookup_flags); diff --git a/fs/isofs/export.c b/fs/isofs/export.c index 1d3804492aa7..2b4f2358eadb 100644 --- a/fs/isofs/export.c +++ b/fs/isofs/export.c @@ -175,7 +175,7 @@ static struct dentry *isofs_fh_to_parent(struct super_block *sb, { struct isofs_fid *ifid = (struct isofs_fid *)fid; - if (fh_type != 2) + if (fh_len < 2 || fh_type != 2) return NULL; return isofs_export_iget(sb, diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 7e355870d519..a2aa97d45670 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -126,7 +126,7 @@ static void restart_grace(void) static int lockd(void *vrqstp) { - int err = 0, preverr = 0; + int err = 0; struct svc_rqst *rqstp = vrqstp; /* try_to_freeze() is called from svc_recv() */ @@ -165,21 +165,8 @@ lockd(void *vrqstp) * recvfrom routine. */ err = svc_recv(rqstp, timeout); - if (err == -EAGAIN || err == -EINTR) { - preverr = err; + if (err == -EAGAIN || err == -EINTR) continue; - } - if (err < 0) { - if (err != preverr) { - printk(KERN_WARNING "%s: unexpected error " - "from svc_recv (%d)\n", __func__, err); - preverr = err; - } - schedule_timeout_interruptible(HZ); - continue; - } - preverr = err; - dprintk("lockd: request from %s\n", svc_print_addr(rqstp, buf, sizeof(buf))); diff --git a/fs/locks.c b/fs/locks.c index abc7dc6c490b..a94e331a52a2 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(__break_lease); void lease_get_mtime(struct inode *inode, struct timespec *time) { struct file_lock *flock = inode->i_flock; - if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK)) + if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK)) *time = current_fs_time(inode->i_sb); else *time = inode->i_mtime; @@ -2185,8 +2185,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, } else { seq_printf(f, "%s ", (lease_breaking(fl)) - ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " - : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); + ? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ " + : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ "); } if (inode) { #ifdef WE_CAN_BREAK_LSLK_NOW diff --git a/fs/namei.c b/fs/namei.c index aa30d19e9edd..d1895f308156 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -117,18 +117,70 @@ * POSIX.1 2.4: an empty pathname is invalid (ENOENT). * PATH_MAX includes the nul terminator --RR. */ -static char *getname_flags(const char __user *filename, int flags, int *empty) +void final_putname(struct filename *name) { - char *result = __getname(), *err; + if (name->separate) { + __putname(name->name); + kfree(name); + } else { + __putname(name); + } +} + +#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) + +static struct filename * +getname_flags(const char __user *filename, int flags, int *empty) +{ + struct filename *result, *err; int len; + long max; + char *kname; + result = audit_reusename(filename); + if (result) + return result; + + result = __getname(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); - len = strncpy_from_user(result, filename, PATH_MAX); - err = ERR_PTR(len); - if (unlikely(len < 0)) + /* + * First, try to embed the struct filename inside the names_cache + * allocation + */ + kname = (char *)result + sizeof(*result); + result->name = kname; + result->separate = false; + max = EMBEDDED_NAME_MAX; + +recopy: + len = strncpy_from_user(kname, filename, max); + if (unlikely(len < 0)) { + err = ERR_PTR(len); goto error; + } + + /* + * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a + * separate struct filename so we can dedicate the entire + * names_cache allocation for the pathname, and re-do the copy from + * userland. + */ + if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) { + kname = (char *)result; + + result = kzalloc(sizeof(*result), GFP_KERNEL); + if (!result) { + err = ERR_PTR(-ENOMEM); + result = (struct filename *)kname; + goto error; + } + result->name = kname; + result->separate = true; + max = PATH_MAX; + goto recopy; + } /* The empty path is special. */ if (unlikely(!len)) { @@ -140,30 +192,32 @@ static char *getname_flags(const char __user *filename, int flags, int *empty) } err = ERR_PTR(-ENAMETOOLONG); - if (likely(len < PATH_MAX)) { - audit_getname(result); - return result; - } + if (unlikely(len >= PATH_MAX)) + goto error; + + result->uptr = filename; + audit_getname(result); + return result; error: - __putname(result); + final_putname(result); return err; } -char *getname(const char __user * filename) +struct filename * +getname(const char __user * filename) { return getname_flags(filename, 0, NULL); } +EXPORT_SYMBOL(getname); #ifdef CONFIG_AUDITSYSCALL -void putname(const char *name) +void putname(struct filename *name) { if (unlikely(!audit_dummy_context())) - audit_putname(name); - else - __putname(name); + return audit_putname(name); + final_putname(name); } -EXPORT_SYMBOL(putname); #endif static int check_acl(struct inode *inode, int mask) @@ -692,9 +746,9 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd) if (uid_eq(parent->i_uid, inode->i_uid)) return 0; + audit_log_link_denied("follow_link", link); path_put_conditional(link, nd); path_put(&nd->path); - audit_log_link_denied("follow_link", link); return -EACCES; } @@ -810,6 +864,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p) return error; out_put_nd_path: + *p = NULL; path_put(&nd->path); path_put(link); return error; @@ -1962,24 +2017,29 @@ static int path_lookupat(int dfd, const char *name, return err; } -static int do_path_lookup(int dfd, const char *name, +static int filename_lookup(int dfd, struct filename *name, unsigned int flags, struct nameidata *nd) { - int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); + int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd); if (unlikely(retval == -ECHILD)) - retval = path_lookupat(dfd, name, flags, nd); + retval = path_lookupat(dfd, name->name, flags, nd); if (unlikely(retval == -ESTALE)) - retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd); + retval = path_lookupat(dfd, name->name, + flags | LOOKUP_REVAL, nd); - if (likely(!retval)) { - if (unlikely(!audit_dummy_context())) { - if (nd->path.dentry && nd->inode) - audit_inode(name, nd->path.dentry); - } - } + if (likely(!retval)) + audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT); return retval; } +static int do_path_lookup(int dfd, const char *name, + unsigned int flags, struct nameidata *nd) +{ + struct filename filename = { .name = name }; + + return filename_lookup(dfd, &filename, flags, nd); +} + /* does lookup, returns the object with parent locked */ struct dentry *kern_path_locked(const char *name, struct path *path) { @@ -2097,13 +2157,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags, struct path *path, int *empty) { struct nameidata nd; - char *tmp = getname_flags(name, flags, empty); + struct filename *tmp = getname_flags(name, flags, empty); int err = PTR_ERR(tmp); if (!IS_ERR(tmp)) { BUG_ON(flags & LOOKUP_PARENT); - err = do_path_lookup(dfd, tmp, flags, &nd); + err = filename_lookup(dfd, tmp, flags, &nd); putname(tmp); if (!err) *path = nd.path; @@ -2117,22 +2177,28 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, return user_path_at_empty(dfd, name, flags, path, NULL); } -static int user_path_parent(int dfd, const char __user *path, - struct nameidata *nd, char **name) +/* + * NB: most callers don't do anything directly with the reference to the + * to struct filename, but the nd->last pointer points into the name string + * allocated by getname. So we must hold the reference to it until all + * path-walking is complete. + */ +static struct filename * +user_path_parent(int dfd, const char __user *path, struct nameidata *nd) { - char *s = getname(path); + struct filename *s = getname(path); int error; if (IS_ERR(s)) - return PTR_ERR(s); + return s; - error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd); - if (error) + error = filename_lookup(dfd, s, LOOKUP_PARENT, nd); + if (error) { putname(s); - else - *name = s; + return ERR_PTR(error); + } - return error; + return s; } /* @@ -2179,7 +2245,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) return -ENOENT; BUG_ON(victim->d_parent->d_inode != dir); - audit_inode_child(victim, dir); + audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); error = inode_permission(dir, MAY_WRITE | MAY_EXEC); if (error) @@ -2624,7 +2690,7 @@ out_dput: */ static int do_last(struct nameidata *nd, struct path *path, struct file *file, const struct open_flags *op, - int *opened, const char *pathname) + int *opened, struct filename *name) { struct dentry *dir = nd->path.dentry; int open_flag = op->open_flag; @@ -2651,7 +2717,7 @@ static int do_last(struct nameidata *nd, struct path *path, error = complete_walk(nd); if (error) return error; - audit_inode(pathname, nd->path.dentry); + audit_inode(name, nd->path.dentry, 0); if (open_flag & O_CREAT) { error = -EISDIR; goto out; @@ -2661,7 +2727,7 @@ static int do_last(struct nameidata *nd, struct path *path, error = complete_walk(nd); if (error) return error; - audit_inode(pathname, dir); + audit_inode(name, dir, 0); goto finish_open; } @@ -2690,7 +2756,7 @@ static int do_last(struct nameidata *nd, struct path *path, if (error) return error; - audit_inode(pathname, dir); + audit_inode(name, dir, 0); error = -EISDIR; /* trailing slashes? */ if (nd->last.name[nd->last.len]) @@ -2720,7 +2786,7 @@ retry_lookup: !S_ISREG(file->f_path.dentry->d_inode->i_mode)) will_truncate = false; - audit_inode(pathname, file->f_path.dentry); + audit_inode(name, file->f_path.dentry, 0); goto opened; } @@ -2737,7 +2803,7 @@ retry_lookup: * create/update audit record if it already exists. */ if (path->dentry->d_inode) - audit_inode(pathname, path->dentry); + audit_inode(name, path->dentry, 0); /* * If atomic_open() acquired write access it is dropped now due to @@ -2802,7 +2868,7 @@ finish_lookup: error = -ENOTDIR; if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup) goto out; - audit_inode(pathname, nd->path.dentry); + audit_inode(name, nd->path.dentry, 0); finish_open: if (!S_ISREG(nd->inode->i_mode)) will_truncate = false; @@ -2870,7 +2936,7 @@ stale_open: goto retry_lookup; } -static struct file *path_openat(int dfd, const char *pathname, +static struct file *path_openat(int dfd, struct filename *pathname, struct nameidata *nd, const struct open_flags *op, int flags) { struct file *base = NULL; @@ -2885,12 +2951,12 @@ static struct file *path_openat(int dfd, const char *pathname, file->f_flags = op->open_flag; - error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); + error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base); if (unlikely(error)) goto out; current->total_link_count = 0; - error = link_path_walk(pathname, nd); + error = link_path_walk(pathname->name, nd); if (unlikely(error)) goto out; @@ -2936,7 +3002,7 @@ out: return file; } -struct file *do_filp_open(int dfd, const char *pathname, +struct file *do_filp_open(int dfd, struct filename *pathname, const struct open_flags *op, int flags) { struct nameidata nd; @@ -2955,6 +3021,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, { struct nameidata nd; struct file *file; + struct filename filename = { .name = name }; nd.root.mnt = mnt; nd.root.dentry = dentry; @@ -2964,11 +3031,11 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN) return ERR_PTR(-ELOOP); - file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); + file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU); if (unlikely(file == ERR_PTR(-ECHILD))) - file = path_openat(-1, name, &nd, op, flags); + file = path_openat(-1, &filename, &nd, op, flags); if (unlikely(file == ERR_PTR(-ESTALE))) - file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL); + file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL); return file; } @@ -3043,11 +3110,11 @@ EXPORT_SYMBOL(done_path_create); struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) { - char *tmp = getname(pathname); + struct filename *tmp = getname(pathname); struct dentry *res; if (IS_ERR(tmp)) return ERR_CAST(tmp); - res = kern_path_create(dfd, tmp, path, is_dir); + res = kern_path_create(dfd, tmp->name, path, is_dir); putname(tmp); return res; } @@ -3252,13 +3319,13 @@ out: static long do_rmdir(int dfd, const char __user *pathname) { int error = 0; - char * name; + struct filename *name; struct dentry *dentry; struct nameidata nd; - error = user_path_parent(dfd, pathname, &nd, &name); - if (error) - return error; + name = user_path_parent(dfd, pathname, &nd); + if (IS_ERR(name)) + return PTR_ERR(name); switch(nd.last_type) { case LAST_DOTDOT: @@ -3347,14 +3414,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) static long do_unlinkat(int dfd, const char __user *pathname) { int error; - char *name; + struct filename *name; struct dentry *dentry; struct nameidata nd; struct inode *inode = NULL; - error = user_path_parent(dfd, pathname, &nd, &name); - if (error) - return error; + name = user_path_parent(dfd, pathname, &nd); + if (IS_ERR(name)) + return PTR_ERR(name); error = -EISDIR; if (nd.last_type != LAST_NORM) @@ -3438,7 +3505,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname) { int error; - char *from; + struct filename *from; struct dentry *dentry; struct path path; @@ -3451,9 +3518,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, if (IS_ERR(dentry)) goto out_putname; - error = security_path_symlink(&path, dentry, from); + error = security_path_symlink(&path, dentry, from->name); if (!error) - error = vfs_symlink(path.dentry->d_inode, dentry, from); + error = vfs_symlink(path.dentry->d_inode, dentry, from->name); done_path_create(&path, dentry); out_putname: putname(from); @@ -3733,17 +3800,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, struct dentry *old_dentry, *new_dentry; struct dentry *trap; struct nameidata oldnd, newnd; - char *from; - char *to; + struct filename *from; + struct filename *to; int error; - error = user_path_parent(olddfd, oldname, &oldnd, &from); - if (error) + from = user_path_parent(olddfd, oldname, &oldnd); + if (IS_ERR(from)) { + error = PTR_ERR(from); goto exit; + } - error = user_path_parent(newdfd, newname, &newnd, &to); - if (error) + to = user_path_parent(newdfd, newname, &newnd); + if (IS_ERR(to)) { + error = PTR_ERR(to); goto exit1; + } error = -EXDEV; if (oldnd.path.mnt != newnd.path.mnt) @@ -3967,7 +4038,6 @@ EXPORT_SYMBOL(follow_down_one); EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(get_write_access); /* nfsd */ -EXPORT_SYMBOL(getname); EXPORT_SYMBOL(lock_rename); EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link_light); diff --git a/fs/namespace.c b/fs/namespace.c index 7bdf7907413f..24960626bb6b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1640,7 +1640,7 @@ static int do_change_type(struct path *path, int flag) /* * do loopback mount. */ -static int do_loopback(struct path *path, char *old_name, +static int do_loopback(struct path *path, const char *old_name, int recurse) { LIST_HEAD(umount_list); @@ -1764,7 +1764,7 @@ static inline int tree_contains_unbindable(struct mount *mnt) return 0; } -static int do_move_mount(struct path *path, char *old_name) +static int do_move_mount(struct path *path, const char *old_name) { struct path old_path, parent_path; struct mount *p; @@ -1917,8 +1917,8 @@ unlock: * create a new mount for userspace and request it to be added into the * namespace's tree */ -static int do_new_mount(struct path *path, char *type, int flags, - int mnt_flags, char *name, void *data) +static int do_new_mount(struct path *path, const char *type, int flags, + int mnt_flags, const char *name, void *data) { struct vfsmount *mnt; int err; @@ -2191,8 +2191,8 @@ int copy_mount_string(const void __user *data, char **where) * Therefore, if this magic number is present, it carries no information * and must be discarded. */ -long do_mount(char *dev_name, char *dir_name, char *type_page, - unsigned long flags, void *data_page) +long do_mount(const char *dev_name, const char *dir_name, + const char *type_page, unsigned long flags, void *data_page) { struct path path; int retval = 0; @@ -2408,7 +2408,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, { int ret; char *kernel_type; - char *kernel_dir; + struct filename *kernel_dir; char *kernel_dev; unsigned long data_page; @@ -2430,7 +2430,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, if (ret < 0) goto out_data; - ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, + ret = do_mount(kernel_dev, kernel_dir->name, kernel_type, flags, (void *) data_page); free_page(data_page); diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 2245bef50f37..9a521fb39869 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -72,7 +72,7 @@ out_err: static int nfs4_callback_svc(void *vrqstp) { - int err, preverr = 0; + int err; struct svc_rqst *rqstp = vrqstp; set_freezable(); @@ -82,20 +82,8 @@ nfs4_callback_svc(void *vrqstp) * Listen for a request on the socket */ err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); - if (err == -EAGAIN || err == -EINTR) { - preverr = err; + if (err == -EAGAIN || err == -EINTR) continue; - } - if (err < 0) { - if (err != preverr) { - printk(KERN_WARNING "NFS: %s: unexpected error " - "from svc_recv (%d)\n", __func__, err); - preverr = err; - } - schedule_timeout_uninterruptible(HZ); - continue; - } - preverr = err; svc_process(rqstp); } return 0; diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 6aa5590c3679..b314888825d5 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -218,8 +218,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, * There must be an encoding function for void results so svc_process * will work properly. */ -int -nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) +static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 9095f3c21df9..97d90d1c8608 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -247,7 +247,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, /* Now create the file and set attributes */ nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, attr, newfhp, - argp->createmode, argp->verf, NULL, NULL); + argp->createmode, (u32 *)argp->verf, NULL, NULL); RETURN_STATUS(nfserr); } diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 4c7bd35b1876..bdf29c96e4cd 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1028,7 +1028,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp) cb->cb_msg.rpc_cred = callback_cred; cb->cb_ops = &nfsd4_cb_recall_ops; - dp->dl_retries = 1; INIT_LIST_HEAD(&cb->cb_per_client); cb->cb_done = true; diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index fdc91a6fc9c4..a1f10c0a6255 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -478,7 +478,7 @@ nfsd_idmap_init(struct net *net) goto destroy_idtoname_cache; nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); if (IS_ERR(nn->nametoid_cache)) { - rv = PTR_ERR(nn->idtoname_cache); + rv = PTR_ERR(nn->nametoid_cache); goto unregister_idtoname_cache; } rv = cache_register_net(nn->nametoid_cache, net); @@ -598,7 +598,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel /* Just to make sure it's null-terminated: */ memcpy(buf, name, namelen); buf[namelen] = '\0'; - ret = kstrtouint(name, 10, id); + ret = kstrtouint(buf, 10, id); return ret == 0; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c9c1c0a25417..6c9a4b291dba 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -370,7 +370,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_PREVIOUS: open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; - status = nfs4_check_open_reclaim(&open->op_clientid); + status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion); if (status) goto out; case NFS4_OPEN_CLAIM_FH: @@ -1054,8 +1054,8 @@ struct nfsd4_operation { char *op_name; /* Try to get response size before operation */ nfsd4op_rsize op_rsize_bop; - stateid_setter op_get_currentstateid; - stateid_getter op_set_currentstateid; + stateid_getter op_get_currentstateid; + stateid_setter op_set_currentstateid; }; static struct nfsd4_operation nfsd4_ops[]; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 48a1bad37334..d0237f872cc4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -758,7 +758,7 @@ static void nfsd4_put_drc_mem(int slotsize, int num) spin_unlock(&nfsd_drc_lock); } -static struct nfsd4_session *alloc_session(int slotsize, int numslots) +static struct nfsd4_session *__alloc_session(int slotsize, int numslots) { struct nfsd4_session *new; int mem, i; @@ -852,35 +852,28 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn) return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); } -static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) +static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) { - struct nfsd4_conn *conn; int ret; - conn = alloc_conn(rqstp, dir); - if (!conn) - return nfserr_jukebox; nfsd4_hash_conn(conn, ses); ret = nfsd4_register_conn(conn); if (ret) /* oops; xprt is already down: */ nfsd4_conn_lost(&conn->cn_xpt_user); - if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN && - dir & NFS4_CDFC4_BACK) { + if (conn->cn_flags & NFS4_CDFC4_BACK) { /* callback channel may be back up */ nfsd4_probe_callback(ses->se_client); } - return nfs_ok; } -static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) +static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) { u32 dir = NFS4_CDFC4_FORE; - if (ses->se_flags & SESSION4_BACK_CHAN) + if (cses->flags & SESSION4_BACK_CHAN) dir |= NFS4_CDFC4_BACK; - - return nfsd4_new_conn(rqstp, ses, dir); + return alloc_conn(rqstp, dir); } /* must be called under client_lock */ @@ -903,20 +896,21 @@ static void nfsd4_del_conns(struct nfsd4_session *s) spin_unlock(&clp->cl_lock); } +static void __free_session(struct nfsd4_session *ses) +{ + nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs); + free_session_slots(ses); + kfree(ses); +} + static void free_session(struct kref *kref) { struct nfsd4_session *ses; - int mem; lockdep_assert_held(&client_lock); ses = container_of(kref, struct nfsd4_session, se_ref); nfsd4_del_conns(ses); - spin_lock(&nfsd_drc_lock); - mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); - nfsd_drc_mem_used -= mem; - spin_unlock(&nfsd_drc_lock); - free_session_slots(ses); - kfree(ses); + __free_session(ses); } void nfsd4_put_session(struct nfsd4_session *ses) @@ -926,14 +920,10 @@ void nfsd4_put_session(struct nfsd4_session *ses) spin_unlock(&client_lock); } -static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) +static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) { struct nfsd4_session *new; - struct nfsd4_channel_attrs *fchan = &cses->fore_channel; int numslots, slotsize; - __be32 status; - int idx; - /* * Note decreasing slot size below client's request may * make it difficult for client to function correctly, whereas @@ -946,12 +936,18 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n if (numslots < 1) return NULL; - new = alloc_session(slotsize, numslots); + new = __alloc_session(slotsize, numslots); if (!new) { nfsd4_put_drc_mem(slotsize, fchan->maxreqs); return NULL; } init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); + return new; +} + +static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) +{ + int idx; new->se_client = clp; gen_sessionid(new); @@ -970,14 +966,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n spin_unlock(&clp->cl_lock); spin_unlock(&client_lock); - status = nfsd4_new_conn_from_crses(rqstp, new); - /* whoops: benny points out, status is ignored! (err, or bogus) */ - if (status) { - spin_lock(&client_lock); - free_session(&new->se_ref); - spin_unlock(&client_lock); - return NULL; - } if (cses->flags & SESSION4_BACK_CHAN) { struct sockaddr *sa = svc_addr(rqstp); /* @@ -990,7 +978,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); } - nfsd4_probe_callback(clp); return new; } @@ -1131,7 +1118,7 @@ unhash_client_locked(struct nfs4_client *clp) } static void -expire_client(struct nfs4_client *clp) +destroy_client(struct nfs4_client *clp) { struct nfs4_openowner *oo; struct nfs4_delegation *dp; @@ -1165,6 +1152,12 @@ expire_client(struct nfs4_client *clp) spin_unlock(&client_lock); } +static void expire_client(struct nfs4_client *clp) +{ + nfsd4_client_record_remove(clp); + destroy_client(clp); +} + static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) { memcpy(target->cl_verifier.data, source->data, @@ -1223,10 +1216,26 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2) return true; } +/* + * RFC 3530 language requires clid_inuse be returned when the + * "principal" associated with a requests differs from that previously + * used. We use uid, gid's, and gss principal string as our best + * approximation. We also don't want to allow non-gss use of a client + * established using gss: in theory cr_principal should catch that + * change, but in practice cr_principal can be null even in the gss case + * since gssd doesn't always pass down a principal string. + */ +static bool is_gss_cred(struct svc_cred *cr) +{ + /* Is cr_flavor one of the gss "pseudoflavors"?: */ + return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); +} + + static bool same_creds(struct svc_cred *cr1, struct svc_cred *cr2) { - if ((cr1->cr_flavor != cr2->cr_flavor) + if ((is_gss_cred(cr1) != is_gss_cred(cr2)) || (cr1->cr_uid != cr2->cr_uid) || (cr1->cr_gid != cr2->cr_gid) || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) @@ -1340,13 +1349,15 @@ move_to_confirmed(struct nfs4_client *clp) } static struct nfs4_client * -find_confirmed_client(clientid_t *clid) +find_confirmed_client(clientid_t *clid, bool sessions) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) { + if ((bool)clp->cl_minorversion != sessions) + return NULL; renew_client(clp); return clp; } @@ -1355,14 +1366,17 @@ find_confirmed_client(clientid_t *clid) } static struct nfs4_client * -find_unconfirmed_client(clientid_t *clid) +find_unconfirmed_client(clientid_t *clid, bool sessions) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { - if (same_clid(&clp->cl_clientid, clid)) + if (same_clid(&clp->cl_clientid, clid)) { + if ((bool)clp->cl_minorversion != sessions) + return NULL; return clp; + } } return NULL; } @@ -1651,6 +1665,7 @@ out_new: status = nfserr_jukebox; goto out; } + new->cl_minorversion = 1; gen_clid(new); add_to_unconfirmed(new, strhashval); @@ -1743,67 +1758,71 @@ nfsd4_create_session(struct svc_rqst *rqstp, struct sockaddr *sa = svc_addr(rqstp); struct nfs4_client *conf, *unconf; struct nfsd4_session *new; + struct nfsd4_conn *conn; struct nfsd4_clid_slot *cs_slot = NULL; - bool confirm_me = false; __be32 status = 0; if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) return nfserr_inval; + if (check_forechannel_attrs(cr_ses->fore_channel)) + return nfserr_toosmall; + new = alloc_session(&cr_ses->fore_channel); + if (!new) + return nfserr_jukebox; + status = nfserr_jukebox; + conn = alloc_conn_from_crses(rqstp, cr_ses); + if (!conn) + goto out_free_session; nfs4_lock_state(); - unconf = find_unconfirmed_client(&cr_ses->clientid); - conf = find_confirmed_client(&cr_ses->clientid); + unconf = find_unconfirmed_client(&cr_ses->clientid, true); + conf = find_confirmed_client(&cr_ses->clientid, true); if (conf) { cs_slot = &conf->cl_cs_slot; status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); if (status == nfserr_replay_cache) { status = nfsd4_replay_create_session(cr_ses, cs_slot); - goto out; + goto out_free_conn; } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { status = nfserr_seq_misordered; - goto out; + goto out_free_conn; } } else if (unconf) { + unsigned int hash; + struct nfs4_client *old; if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { status = nfserr_clid_inuse; - goto out; + goto out_free_conn; } cs_slot = &unconf->cl_cs_slot; status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); if (status) { /* an unconfirmed replay returns misordered */ status = nfserr_seq_misordered; - goto out; + goto out_free_conn; } - confirm_me = true; + hash = clientstr_hashval(unconf->cl_recdir); + old = find_confirmed_client_by_str(unconf->cl_recdir, hash); + if (old) + expire_client(old); + move_to_confirmed(unconf); conf = unconf; } else { status = nfserr_stale_clientid; - goto out; + goto out_free_conn; } - - /* - * XXX: we should probably set this at creation time, and check - * for consistent minorversion use throughout: - */ - conf->cl_minorversion = 1; + status = nfs_ok; /* * We do not support RDMA or persistent sessions */ cr_ses->flags &= ~SESSION4_PERSIST; cr_ses->flags &= ~SESSION4_RDMA; - status = nfserr_toosmall; - if (check_forechannel_attrs(cr_ses->fore_channel)) - goto out; + init_session(rqstp, new, conf, cr_ses); + nfsd4_init_conn(rqstp, conn, new); - status = nfserr_jukebox; - new = alloc_init_session(rqstp, conf, cr_ses); - if (!new) - goto out; - status = nfs_ok; memcpy(cr_ses->sessionid.data, new->se_sessionid.data, NFS4_MAX_SESSIONID_LEN); memcpy(&cr_ses->fore_channel, &new->se_fchannel, @@ -1813,18 +1832,15 @@ nfsd4_create_session(struct svc_rqst *rqstp, /* cache solo and embedded create sessions under the state lock */ nfsd4_cache_create_session(cr_ses, cs_slot, status); - if (confirm_me) { - unsigned int hash = clientstr_hashval(unconf->cl_recdir); - struct nfs4_client *old = - find_confirmed_client_by_str(conf->cl_recdir, hash); - if (old) - expire_client(old); - move_to_confirmed(conf); - } out: nfs4_unlock_state(); dprintk("%s returns %d\n", __func__, ntohl(status)); return status; +out_free_conn: + free_conn(conn); +out_free_session: + __free_session(new); + goto out; } static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) @@ -1854,6 +1870,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, struct nfsd4_bind_conn_to_session *bcts) { __be32 status; + struct nfsd4_conn *conn; if (!nfsd4_last_compound_op(rqstp)) return nfserr_not_only_op; @@ -1870,9 +1887,13 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, return nfserr_badsession; status = nfsd4_map_bcts_dir(&bcts->dir); - if (!status) - nfsd4_new_conn(rqstp, cstate->session, bcts->dir); - return status; + if (status) + return status; + conn = alloc_conn(rqstp, bcts->dir); + if (!conn) + return nfserr_jukebox; + nfsd4_init_conn(rqstp, conn, cstate->session); + return nfs_ok; } static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) @@ -2085,8 +2106,8 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta __be32 status = 0; nfs4_lock_state(); - unconf = find_unconfirmed_client(&dc->clientid); - conf = find_confirmed_client(&dc->clientid); + unconf = find_unconfirmed_client(&dc->clientid, true); + conf = find_confirmed_client(&dc->clientid, true); if (conf) { clp = conf; @@ -2200,10 +2221,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, copy_clid(new, conf); else /* case 4 (new client) or cases 2, 3 (client reboot): */ gen_clid(new); - /* - * XXX: we should probably set this at creation time, and check - * for consistent minorversion use throughout: - */ new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); add_to_unconfirmed(new, strhashval); @@ -2232,8 +2249,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, return nfserr_stale_clientid; nfs4_lock_state(); - conf = find_confirmed_client(clid); - unconf = find_unconfirmed_client(clid); + conf = find_confirmed_client(clid, false); + unconf = find_unconfirmed_client(clid, false); /* * We try hard to give out unique clientid's, so if we get an * attempt to confirm the same clientid with a different cred, @@ -2262,10 +2279,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, unsigned int hash = clientstr_hashval(unconf->cl_recdir); conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); - if (conf) { - nfsd4_client_record_remove(conf); + if (conf) expire_client(conf); - } move_to_confirmed(unconf); nfsd4_probe_callback(unconf); } @@ -2447,16 +2462,20 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, } static struct nfs4_openowner * -find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) +find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions) { struct nfs4_stateowner *so; struct nfs4_openowner *oo; + struct nfs4_client *clp; list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { if (!so->so_is_open_owner) continue; if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { oo = openowner(so); + clp = oo->oo_owner.so_client; + if ((bool)clp->cl_minorversion != sessions) + return NULL; renew_client(oo->oo_owner.so_client); return oo; } @@ -2600,10 +2619,10 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, return nfserr_jukebox; strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); - oo = find_openstateowner_str(strhashval, open); + oo = find_openstateowner_str(strhashval, open, cstate->minorversion); open->op_openowner = oo; if (!oo) { - clp = find_confirmed_client(clientid); + clp = find_confirmed_client(clientid, cstate->minorversion); if (clp == NULL) return nfserr_expired; goto new_owner; @@ -2705,11 +2724,6 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st return nfs_ok; } -static void nfs4_free_stateid(struct nfs4_ol_stateid *s) -{ - kmem_cache_free(stateid_slab, s); -} - static inline int nfs4_access_to_access(u32 nfs4_access) { int flags = 0; @@ -3087,7 +3101,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) if (open->op_file) nfsd4_free_file(open->op_file); if (open->op_stp) - nfs4_free_stateid(open->op_stp); + free_generic_stateid(open->op_stp); } __be32 @@ -3104,7 +3118,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_stale_clientid; if (STALE_CLIENTID(clid, nn)) goto out; - clp = find_confirmed_client(clid); + clp = find_confirmed_client(clid, cstate->minorversion); status = nfserr_expired; if (clp == NULL) { /* We assume the client took too long to RENEW. */ @@ -3180,7 +3194,6 @@ nfs4_laundromat(void) clp = list_entry(pos, struct nfs4_client, cl_lru); dprintk("NFSD: purging unused client (clientid %08x)\n", clp->cl_clientid.cl_id); - nfsd4_client_record_remove(clp); expire_client(clp); } spin_lock(&recall_lock); @@ -3372,7 +3385,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) return nfs_ok; } -static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s) +static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions) { struct nfs4_client *cl; struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); @@ -3381,7 +3394,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s return nfserr_bad_stateid; if (STALE_STATEID(stateid, nn)) return nfserr_stale_stateid; - cl = find_confirmed_client(&stateid->si_opaque.so_clid); + cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); if (!cl) return nfserr_expired; *s = find_stateid_by_type(cl, stateid, typemask); @@ -3414,7 +3427,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return check_special_stateids(net, current_fh, stateid, flags); - status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion); if (status) return status; status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); @@ -3564,7 +3577,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, seqid, STATEID_VAL(stateid)); *stpp = NULL; - status = nfsd4_lookup_stateid(stateid, typemask, &s); + status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion); if (status) return status; *stpp = openlockstateid(s); @@ -3765,6 +3778,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); nfsd4_close_open_stateid(stp); + release_last_closed_stateid(oo); oo->oo_last_closed_stid = stp; if (list_empty(&oo->oo_owner.so_stateids)) { @@ -3801,7 +3815,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, inode = cstate->current_fh.fh_dentry->d_inode; nfs4_lock_state(); - status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); if (status) goto out; dp = delegstateid(s); @@ -4045,8 +4059,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_lockowner *lock_sop = NULL; struct nfs4_ol_stateid *lock_stp; struct file *filp = NULL; - struct file_lock file_lock; - struct file_lock conflock; + struct file_lock *file_lock = NULL; + struct file_lock *conflock = NULL; __be32 status = 0; bool new_state = false; int lkflg; @@ -4116,21 +4130,28 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) goto out; - locks_init_lock(&file_lock); + file_lock = locks_alloc_lock(); + if (!file_lock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } + + locks_init_lock(file_lock); switch (lock->lk_type) { case NFS4_READ_LT: case NFS4_READW_LT: filp = find_readable_file(lock_stp->st_file); if (filp) get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); - file_lock.fl_type = F_RDLCK; + file_lock->fl_type = F_RDLCK; break; case NFS4_WRITE_LT: case NFS4_WRITEW_LT: filp = find_writeable_file(lock_stp->st_file); if (filp) get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); - file_lock.fl_type = F_WRLCK; + file_lock->fl_type = F_WRLCK; break; default: status = nfserr_inval; @@ -4140,22 +4161,23 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_openmode; goto out; } - file_lock.fl_owner = (fl_owner_t)lock_sop; - file_lock.fl_pid = current->tgid; - file_lock.fl_file = filp; - file_lock.fl_flags = FL_POSIX; - file_lock.fl_lmops = &nfsd_posix_mng_ops; - - file_lock.fl_start = lock->lk_offset; - file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); - nfs4_transform_lock_offset(&file_lock); - - /* - * Try to lock the file in the VFS. - * Note: locks.c uses the BKL to protect the inode's lock list. - */ + file_lock->fl_owner = (fl_owner_t)lock_sop; + file_lock->fl_pid = current->tgid; + file_lock->fl_file = filp; + file_lock->fl_flags = FL_POSIX; + file_lock->fl_lmops = &nfsd_posix_mng_ops; + file_lock->fl_start = lock->lk_offset; + file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); + nfs4_transform_lock_offset(file_lock); + + conflock = locks_alloc_lock(); + if (!conflock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } - err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); + err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); switch (-err) { case 0: /* success! */ update_stateid(&lock_stp->st_stid.sc_stateid); @@ -4166,7 +4188,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, case (EAGAIN): /* conflock holds conflicting lock */ status = nfserr_denied; dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); - nfs4_set_lock_denied(&conflock, &lock->lk_denied); + nfs4_set_lock_denied(conflock, &lock->lk_denied); break; case (EDEADLK): status = nfserr_deadlock; @@ -4181,6 +4203,10 @@ out: release_lockowner(lock_sop); if (!cstate->replay_owner) nfs4_unlock_state(); + if (file_lock) + locks_free_lock(file_lock); + if (conflock) + locks_free_lock(conflock); return status; } @@ -4209,7 +4235,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_lockt *lockt) { struct inode *inode; - struct file_lock file_lock; + struct file_lock *file_lock = NULL; struct nfs4_lockowner *lo; __be32 status; struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); @@ -4230,15 +4256,21 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; inode = cstate->current_fh.fh_dentry->d_inode; - locks_init_lock(&file_lock); + file_lock = locks_alloc_lock(); + if (!file_lock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } + locks_init_lock(file_lock); switch (lockt->lt_type) { case NFS4_READ_LT: case NFS4_READW_LT: - file_lock.fl_type = F_RDLCK; + file_lock->fl_type = F_RDLCK; break; case NFS4_WRITE_LT: case NFS4_WRITEW_LT: - file_lock.fl_type = F_WRLCK; + file_lock->fl_type = F_WRLCK; break; default: dprintk("NFSD: nfs4_lockt: bad lock type!\n"); @@ -4248,25 +4280,27 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); if (lo) - file_lock.fl_owner = (fl_owner_t)lo; - file_lock.fl_pid = current->tgid; - file_lock.fl_flags = FL_POSIX; + file_lock->fl_owner = (fl_owner_t)lo; + file_lock->fl_pid = current->tgid; + file_lock->fl_flags = FL_POSIX; - file_lock.fl_start = lockt->lt_offset; - file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); + file_lock->fl_start = lockt->lt_offset; + file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); - nfs4_transform_lock_offset(&file_lock); + nfs4_transform_lock_offset(file_lock); - status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); + status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); if (status) goto out; - if (file_lock.fl_type != F_UNLCK) { + if (file_lock->fl_type != F_UNLCK) { status = nfserr_denied; - nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); + nfs4_set_lock_denied(file_lock, &lockt->lt_denied); } out: nfs4_unlock_state(); + if (file_lock) + locks_free_lock(file_lock); return status; } @@ -4276,7 +4310,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct nfs4_ol_stateid *stp; struct file *filp = NULL; - struct file_lock file_lock; + struct file_lock *file_lock = NULL; __be32 status; int err; @@ -4298,23 +4332,29 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_lock_range; goto out; } - BUG_ON(!filp); - locks_init_lock(&file_lock); - file_lock.fl_type = F_UNLCK; - file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); - file_lock.fl_pid = current->tgid; - file_lock.fl_file = filp; - file_lock.fl_flags = FL_POSIX; - file_lock.fl_lmops = &nfsd_posix_mng_ops; - file_lock.fl_start = locku->lu_offset; - - file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length); - nfs4_transform_lock_offset(&file_lock); + file_lock = locks_alloc_lock(); + if (!file_lock) { + dprintk("NFSD: %s: unable to allocate lock!\n", __func__); + status = nfserr_jukebox; + goto out; + } + locks_init_lock(file_lock); + file_lock->fl_type = F_UNLCK; + file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); + file_lock->fl_pid = current->tgid; + file_lock->fl_file = filp; + file_lock->fl_flags = FL_POSIX; + file_lock->fl_lmops = &nfsd_posix_mng_ops; + file_lock->fl_start = locku->lu_offset; + + file_lock->fl_end = last_byte_offset(locku->lu_offset, + locku->lu_length); + nfs4_transform_lock_offset(file_lock); /* * Try to unlock the file in the VFS. */ - err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); + err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); if (err) { dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); goto out_nfserr; @@ -4328,6 +4368,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, out: if (!cstate->replay_owner) nfs4_unlock_state(); + if (file_lock) + locks_free_lock(file_lock); return status; out_nfserr: @@ -4501,12 +4543,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp) * Called from OPEN. Look for clientid in reclaim list. */ __be32 -nfs4_check_open_reclaim(clientid_t *clid) +nfs4_check_open_reclaim(clientid_t *clid, bool sessions) { struct nfs4_client *clp; /* find clientid in conf_id_hashtbl */ - clp = find_confirmed_client(clid); + clp = find_confirmed_client(clid, sessions); if (clp == NULL) return nfserr_reclaim_bad; @@ -4522,7 +4564,6 @@ void nfsd_forget_clients(u64 num) nfs4_lock_state(); list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { - nfsd4_client_record_remove(clp); expire_client(clp); if (++count == num) break; @@ -4582,7 +4623,7 @@ void nfsd_forget_openowners(u64 num) printk(KERN_INFO "NFSD: Forgot %d open owners", count); } -int nfsd_process_n_delegations(u64 num, struct list_head *list) +static int nfsd_process_n_delegations(u64 num, struct list_head *list) { int i, count = 0; struct nfs4_file *fp, *fnext; @@ -4747,11 +4788,11 @@ __nfs4_state_shutdown(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) { while (!list_empty(&conf_id_hashtbl[i])) { clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); - expire_client(clp); + destroy_client(clp); } while (!list_empty(&unconf_str_hashtbl[i])) { clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); - expire_client(clp); + destroy_client(clp); } } INIT_LIST_HEAD(&reaplist); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6322df36031f..fd548d155088 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2659,7 +2659,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8); WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); WRITE32(bcts->dir); - /* XXX: ? */ + /* Sorry, we do not yet support RDMA over 4.1: */ WRITE32(0); ADJUST_ARGS(); } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index fa49cff5ee65..dab350dfc376 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -406,7 +406,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) return rv; if (newthreads < 0) return -EINVAL; - rv = nfsd_svc(NFS_PORT, newthreads); + rv = nfsd_svc(newthreads); if (rv < 0) return rv; } else @@ -683,25 +683,6 @@ static ssize_t __write_ports_addfd(char *buf) } /* - * A '-' followed by the 'name' of a socket means we close the socket. - */ -static ssize_t __write_ports_delfd(char *buf) -{ - char *toclose; - int len = 0; - - toclose = kstrdup(buf + 1, GFP_KERNEL); - if (toclose == NULL) - return -ENOMEM; - - if (nfsd_serv != NULL) - len = svc_sock_names(nfsd_serv, buf, - SIMPLE_TRANSACTION_LIMIT, toclose); - kfree(toclose); - return len; -} - -/* * A transport listener is added by writing it's transport name and * a port number. */ @@ -712,7 +693,7 @@ static ssize_t __write_ports_addxprt(char *buf) int port, err; struct net *net = &init_net; - if (sscanf(buf, "%15s %4u", transport, &port) != 2) + if (sscanf(buf, "%15s %5u", transport, &port) != 2) return -EINVAL; if (port < 1 || port > USHRT_MAX) @@ -746,31 +727,6 @@ out_err: return err; } -/* - * A transport listener is removed by writing a "-", it's transport - * name, and it's port number. - */ -static ssize_t __write_ports_delxprt(char *buf) -{ - struct svc_xprt *xprt; - char transport[16]; - int port; - - if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) - return -EINVAL; - - if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) - return -EINVAL; - - xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); - if (xprt == NULL) - return -ENOTCONN; - - svc_close_xprt(xprt); - svc_xprt_put(xprt); - return 0; -} - static ssize_t __write_ports(struct file *file, char *buf, size_t size) { if (size == 0) @@ -779,15 +735,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) if (isdigit(buf[0])) return __write_ports_addfd(buf); - if (buf[0] == '-' && isdigit(buf[1])) - return __write_ports_delfd(buf); - if (isalpha(buf[0])) return __write_ports_addxprt(buf); - if (buf[0] == '-' && isalpha(buf[1])) - return __write_ports_delxprt(buf); - return -EINVAL; } @@ -825,21 +775,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) * OR * * Input: - * buf: C string containing a "-" followed - * by an integer value representing a - * previously passed in socket file - * descriptor - * size: non-zero length of C string in @buf - * Output: - * On success: NFS service no longer listens on that socket; - * passed-in buffer filled with a '\n'-terminated C - * string containing a unique name of the listener; - * return code is the size in bytes of the string - * On error: return code is a negative errno value - * - * OR - * - * Input: * buf: C string containing a transport * name and an unsigned integer value * representing the port to listen on, @@ -848,19 +783,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) * Output: * On success: returns zero; NFS service is started * On error: return code is a negative errno value - * - * OR - * - * Input: - * buf: C string containing a "-" followed - * by a transport name and an unsigned - * integer value representing the port - * to listen on, separated by whitespace - * size: non-zero length of C string in @buf - * Output: - * On success: returns zero; NFS service no longer listens - * on that transport - * On error: return code is a negative errno value */ static ssize_t write_ports(struct file *file, char *buf, size_t size) { @@ -1008,8 +930,6 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size) return nfsd4_write_time(file, buf, size, &nfsd4_grace); } -extern char *nfs4_recoverydir(void); - static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) { char *mesg = buf; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 2244222368ab..80d5ce40aadb 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -65,7 +65,7 @@ extern const struct seq_operations nfs_exports_op; /* * Function prototypes. */ -int nfsd_svc(unsigned short port, int nrservs); +int nfsd_svc(int nrservs); int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); int nfsd_nrthreads(void); @@ -124,6 +124,7 @@ int nfs4_state_start(void); void nfs4_state_shutdown(void); void nfs4_reset_lease(time_t leasetime); int nfs4_reset_recoverydir(char *recdir); +char * nfs4_recoverydir(void); #else static inline void nfs4_state_init(void) { } static inline int nfsd4_init_slabs(void) { return 0; } @@ -132,6 +133,7 @@ static inline int nfs4_state_start(void) { return 0; } static inline void nfs4_state_shutdown(void) { } static inline void nfs4_reset_lease(time_t leasetime) { } static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } +static inline char * nfs4_recoverydir(void) {return NULL; } #endif /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 240473cb708f..2013aa001dab 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -183,18 +183,18 @@ int nfsd_nrthreads(void) return rv; } -static int nfsd_init_socks(int port) +static int nfsd_init_socks(void) { int error; if (!list_empty(&nfsd_serv->sv_permsocks)) return 0; - error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port, + error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; - error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port, + error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; @@ -204,7 +204,7 @@ static int nfsd_init_socks(int port) static bool nfsd_up = false; -static int nfsd_startup(unsigned short port, int nrservs) +static int nfsd_startup(int nrservs) { int ret; @@ -218,7 +218,7 @@ static int nfsd_startup(unsigned short port, int nrservs) ret = nfsd_racache_init(2*nrservs); if (ret) return ret; - ret = nfsd_init_socks(port); + ret = nfsd_init_socks(); if (ret) goto out_racache; ret = lockd_up(&init_net); @@ -436,7 +436,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) * this is the first time nrservs is nonzero. */ int -nfsd_svc(unsigned short port, int nrservs) +nfsd_svc(int nrservs) { int error; bool nfsd_up_before; @@ -458,7 +458,7 @@ nfsd_svc(unsigned short port, int nrservs) nfsd_up_before = nfsd_up; - error = nfsd_startup(port, nrservs); + error = nfsd_startup(nrservs); if (error) goto out_destroy; error = svc_set_num_threads(nfsd_serv, NULL, nrservs); @@ -487,7 +487,7 @@ static int nfsd(void *vrqstp) { struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; - int err, preverr = 0; + int err; /* Lock module and set up kernel thread */ mutex_lock(&nfsd_mutex); @@ -534,16 +534,6 @@ nfsd(void *vrqstp) ; if (err == -EINTR) break; - else if (err < 0) { - if (err != preverr) { - printk(KERN_WARNING "%s: unexpected error " - "from svc_recv (%d)\n", __func__, -err); - preverr = err; - } - schedule_timeout_uninterruptible(HZ); - continue; - } - validate_process_creds(); svc_process(rqstp); validate_process_creds(); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 22bd0a66c356..e036894bce57 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -373,11 +373,7 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) return container_of(so, struct nfs4_lockowner, lo_owner); } -/* -* nfs4_file: a file opened by some number of (open) nfs4_stateowners. -* o fi_perfile list is used to search for conflicting -* share_acces, share_deny on the file. -*/ +/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */ struct nfs4_file { atomic_t fi_ref; struct list_head fi_hash; /* hash by "struct inode *" */ @@ -459,7 +455,7 @@ extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); extern void nfs4_release_reclaim(void); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); -extern __be32 nfs4_check_open_reclaim(clientid_t *clid); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *); extern int set_callback_cred(void); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 3f67b8e12251..c120b48ec305 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1581,7 +1581,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) */ oldfs = get_fs(); set_fs(KERNEL_DS); - host_err = inode->i_op->readlink(path.dentry, buf, *lenp); + host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp); set_fs(oldfs); if (host_err < 0) diff --git a/fs/open.c b/fs/open.c index 44da0feeca2c..59071f55bf7f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -478,7 +478,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) file = fget(fd); if (file) { - audit_inode(NULL, file->f_path.dentry); + audit_inode(NULL, file->f_path.dentry, 0); err = chmod_common(&file->f_path, mode); fput(file); } @@ -588,7 +588,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) error = mnt_want_write_file(f.file); if (error) goto out_fput; - audit_inode(NULL, f.file->f_path.dentry); + audit_inode(NULL, f.file->f_path.dentry, 0); error = chown_common(&f.file->f_path, user, group); mnt_drop_write_file(f.file); out_fput: @@ -859,6 +859,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o } /** + * file_open_name - open file and return file pointer + * + * @name: struct filename containing path to open + * @flags: open flags as per the open(2) second argument + * @mode: mode for the new file if O_CREAT is set, else ignored + * + * This is the helper to open a file from kernelspace if you really + * have to. But in generally you should not do this, so please move + * along, nothing to see here.. + */ +struct file *file_open_name(struct filename *name, int flags, umode_t mode) +{ + struct open_flags op; + int lookup = build_open_flags(flags, mode, &op); + return do_filp_open(AT_FDCWD, name, &op, lookup); +} + +/** * filp_open - open file and return file pointer * * @filename: path to open @@ -871,9 +889,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o */ struct file *filp_open(const char *filename, int flags, umode_t mode) { - struct open_flags op; - int lookup = build_open_flags(flags, mode, &op); - return do_filp_open(AT_FDCWD, filename, &op, lookup); + struct filename name = {.name = filename}; + return file_open_name(&name, flags, mode); } EXPORT_SYMBOL(filp_open); @@ -895,7 +912,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; int lookup = build_open_flags(flags, mode, &op); - char *tmp = getname(filename); + struct filename *tmp = getname(filename); int fd = PTR_ERR(tmp); if (!IS_ERR(tmp)) { diff --git a/fs/proc/base.c b/fs/proc/base.c index ef5c84be66f9..144a96732dd7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2258,7 +2258,8 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) pid_t tgid = task_tgid_nr_ns(current, ns); char *name = ERR_PTR(-ENOENT); if (tgid) { - name = __getname(); + /* 11 for max length of signed int in decimal + NULL term */ + name = kmalloc(12, GFP_KERNEL); if (!name) name = ERR_PTR(-ENOMEM); else @@ -2273,7 +2274,7 @@ static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, { char *s = nd_get_link(nd); if (!IS_ERR(s)) - __putname(s); + kfree(s); } static const struct inode_operations proc_self_inode_operations = { diff --git a/fs/quota/quota.c b/fs/quota/quota.c index ff0135d6bc51..af1661f7a54f 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -331,11 +331,11 @@ static struct super_block *quotactl_block(const char __user *special, int cmd) #ifdef CONFIG_BLOCK struct block_device *bdev; struct super_block *sb; - char *tmp = getname(special); + struct filename *tmp = getname(special); if (IS_ERR(tmp)) return ERR_CAST(tmp); - bdev = lookup_bdev(tmp); + bdev = lookup_bdev(tmp->name); putname(tmp); if (IS_ERR(bdev)) return ERR_CAST(bdev); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 46485557cdc6..f27f01a98aa2 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1573,8 +1573,10 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, reiserfs_warning(sb, "reiserfs-13077", "nfsd/reiserfs, fhtype=%d, len=%d - odd", fh_type, fh_len); - fh_type = 5; + fh_type = fh_len; } + if (fh_len < 2) + return NULL; return reiserfs_get_dentry(sb, fid->raw[0], fid->raw[1], (fh_type == 3 || fh_type >= 5) ? fid->raw[2] : 0); @@ -1583,6 +1585,8 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { + if (fh_type > fh_len) + fh_type = fh_len; if (fh_type < 4) return NULL; diff --git a/fs/super.c b/fs/super.c index a3bc935069d9..12f123712161 100644 --- a/fs/super.c +++ b/fs/super.c @@ -186,15 +186,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) spin_lock_init(&s->s_inode_lru_lock); INIT_LIST_HEAD(&s->s_mounts); init_rwsem(&s->s_umount); - mutex_init(&s->s_lock); lockdep_set_class(&s->s_umount, &type->s_umount_key); /* - * The locking rules for s_lock are up to the - * filesystem. For example ext3fs has different - * lock ordering than usbfs: - */ - lockdep_set_class(&s->s_lock, &type->s_lock_key); - /* * sget() can have s_umount recursion. * * When it cannot find a suitable sb, it allocates a new @@ -394,22 +387,6 @@ bool grab_super_passive(struct super_block *sb) return false; } -/* - * Superblock locking. We really ought to get rid of these two. - */ -void lock_super(struct super_block * sb) -{ - mutex_lock(&sb->s_lock); -} - -void unlock_super(struct super_block * sb) -{ - mutex_unlock(&sb->s_lock); -} - -EXPORT_SYMBOL(lock_super); -EXPORT_SYMBOL(unlock_super); - /** * generic_shutdown_super - common helper for ->kill_sb() * @sb: superblock to kill diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c index 9a6ad96acf27..921c053fc052 100644 --- a/fs/sysv/balloc.c +++ b/fs/sysv/balloc.c @@ -60,12 +60,12 @@ void sysv_free_block(struct super_block * sb, sysv_zone_t nr) return; } - lock_super(sb); + mutex_lock(&sbi->s_lock); count = fs16_to_cpu(sbi, *sbi->s_bcache_count); if (count > sbi->s_flc_size) { printk("sysv_free_block: flc_count > flc_size\n"); - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return; } /* If the free list head in super-block is full, it is copied @@ -77,7 +77,7 @@ void sysv_free_block(struct super_block * sb, sysv_zone_t nr) bh = sb_getblk(sb, block); if (!bh) { printk("sysv_free_block: getblk() failed\n"); - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return; } memset(bh->b_data, 0, sb->s_blocksize); @@ -93,7 +93,7 @@ void sysv_free_block(struct super_block * sb, sysv_zone_t nr) *sbi->s_bcache_count = cpu_to_fs16(sbi, count); fs32_add(sbi, sbi->s_free_blocks, 1); dirty_sb(sb); - unlock_super(sb); + mutex_unlock(&sbi->s_lock); } sysv_zone_t sysv_new_block(struct super_block * sb) @@ -104,7 +104,7 @@ sysv_zone_t sysv_new_block(struct super_block * sb) struct buffer_head * bh; unsigned count; - lock_super(sb); + mutex_lock(&sbi->s_lock); count = fs16_to_cpu(sbi, *sbi->s_bcache_count); if (count == 0) /* Applies only to Coherent FS */ @@ -147,11 +147,11 @@ sysv_zone_t sysv_new_block(struct super_block * sb) /* Now the free list head in the superblock is valid again. */ fs32_add(sbi, sbi->s_free_blocks, -1); dirty_sb(sb); - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return nr; Enospc: - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return 0; } @@ -173,7 +173,7 @@ unsigned long sysv_count_free_blocks(struct super_block * sb) if (sbi->s_type == FSTYPE_AFS) return 0; - lock_super(sb); + mutex_lock(&sbi->s_lock); sb_count = fs32_to_cpu(sbi, *sbi->s_free_blocks); if (0) @@ -211,7 +211,7 @@ unsigned long sysv_count_free_blocks(struct super_block * sb) if (count != sb_count) goto Ecount; done: - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return count; Einval: diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index 8233b02eccae..f9db4eb31db4 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -118,7 +118,7 @@ void sysv_free_inode(struct inode * inode) "%s\n", inode->i_sb->s_id); return; } - lock_super(sb); + mutex_lock(&sbi->s_lock); count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count); if (count < sbi->s_fic_size) { *sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sbi, ino); @@ -128,7 +128,7 @@ void sysv_free_inode(struct inode * inode) dirty_sb(sb); memset(raw_inode, 0, sizeof(struct sysv_inode)); mark_buffer_dirty(bh); - unlock_super(sb); + mutex_unlock(&sbi->s_lock); brelse(bh); } @@ -147,13 +147,13 @@ struct inode * sysv_new_inode(const struct inode * dir, umode_t mode) if (!inode) return ERR_PTR(-ENOMEM); - lock_super(sb); + mutex_lock(&sbi->s_lock); count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count); if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) { count = refill_free_cache(sb); if (count == 0) { iput(inode); - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return ERR_PTR(-ENOSPC); } } @@ -174,7 +174,7 @@ struct inode * sysv_new_inode(const struct inode * dir, umode_t mode) sysv_write_inode(inode, &wbc); /* ensure inode not allocated again */ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ /* That's it. */ - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return inode; } @@ -185,7 +185,7 @@ unsigned long sysv_count_free_inodes(struct super_block * sb) struct sysv_inode * raw_inode; int ino, count, sb_count; - lock_super(sb); + mutex_lock(&sbi->s_lock); sb_count = fs16_to_cpu(sbi, *sbi->s_sb_total_free_inodes); @@ -213,7 +213,7 @@ unsigned long sysv_count_free_inodes(struct super_block * sb) if (count != sb_count) goto Einval; out: - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return count; Einval: diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d33e506c1eac..c327d4ee1235 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -36,7 +36,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait) struct sysv_sb_info *sbi = SYSV_SB(sb); unsigned long time = get_seconds(), old_time; - lock_super(sb); + mutex_lock(&sbi->s_lock); /* * If we are going to write out the super block, @@ -51,7 +51,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait) mark_buffer_dirty(sbi->s_bh2); } - unlock_super(sb); + mutex_unlock(&sbi->s_lock); return 0; } diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 7491c33b6468..a38e87bdd78d 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -368,6 +368,7 @@ static int sysv_fill_super(struct super_block *sb, void *data, int silent) sbi->s_sb = sb; sbi->s_block_base = 0; + mutex_init(&sbi->s_lock); sb->s_fs_info = sbi; sb_set_blocksize(sb, BLOCK_SIZE); diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 0bc35fdc58e2..69d488986cce 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -58,6 +58,7 @@ struct sysv_sb_info { u32 s_nzones; /* same as s_sbd->s_fsize */ u16 s_namelen; /* max length of dir entry */ int s_forced_ro; + struct mutex s_lock; }; /* diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 1b3e410bf334..a7ea492ae660 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -54,7 +54,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) if (ufs_fragnum(fragment) + count > uspi->s_fpg) ufs_error (sb, "ufs_free_fragments", "internal error"); - lock_super(sb); + mutex_lock(&UFS_SB(sb)->s_lock); cgno = ufs_dtog(uspi, fragment); bit = ufs_dtogd(uspi, fragment); @@ -118,12 +118,12 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) ubh_sync_block(UCPI_UBH(ucpi)); ufs_mark_sb_dirty(sb); - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT\n"); return; failed: - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT (FAILED)\n"); return; } @@ -155,7 +155,7 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count) goto failed; } - lock_super(sb); + mutex_lock(&UFS_SB(sb)->s_lock); do_more: overflow = 0; @@ -215,12 +215,12 @@ do_more: } ufs_mark_sb_dirty(sb); - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT\n"); return; failed_unlock: - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); failed: UFSD("EXIT (FAILED)\n"); return; @@ -361,7 +361,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, usb1 = ubh_get_usb_first(uspi); *err = -ENOSPC; - lock_super (sb); + mutex_lock(&UFS_SB(sb)->s_lock); tmp = ufs_data_ptr_to_cpu(sb, p); if (count + ufs_fragnum(fragment) > uspi->s_fpb) { @@ -382,19 +382,19 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, "fragment %llu, tmp %llu\n", (unsigned long long)fragment, (unsigned long long)tmp); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); return INVBLOCK; } if (fragment < UFS_I(inode)->i_lastfrag) { UFSD("EXIT (ALREADY ALLOCATED)\n"); - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); return 0; } } else { if (tmp) { UFSD("EXIT (ALREADY ALLOCATED)\n"); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); return 0; } } @@ -403,7 +403,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, * There is not enough space for user on the device */ if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT (FAILED)\n"); return 0; } @@ -428,7 +428,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); } - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } @@ -443,7 +443,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, fragment + count); ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } @@ -481,7 +481,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); if (newcount < request) ufs_free_fragments (inode, result + newcount, request - newcount); ufs_free_fragments (inode, tmp, oldcount); @@ -489,7 +489,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, return result; } - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT (FAILED)\n"); return 0; } diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index e84cbe21b986..d0426d74817b 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -71,11 +71,11 @@ void ufs_free_inode (struct inode * inode) ino = inode->i_ino; - lock_super (sb); + mutex_lock(&UFS_SB(sb)->s_lock); if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) { ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino); - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); return; } @@ -83,7 +83,7 @@ void ufs_free_inode (struct inode * inode) bit = ufs_inotocgoff (ino); ucpi = ufs_load_cylinder (sb, cg); if (!ucpi) { - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); return; } ucg = ubh_get_ucg(UCPI_UBH(ucpi)); @@ -117,7 +117,7 @@ void ufs_free_inode (struct inode * inode) ubh_sync_block(UCPI_UBH(ucpi)); ufs_mark_sb_dirty(sb); - unlock_super (sb); + mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT\n"); } @@ -197,7 +197,7 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode) uspi = sbi->s_uspi; usb1 = ubh_get_usb_first(uspi); - lock_super (sb); + mutex_lock(&sbi->s_lock); /* * Try to place the inode in its parent directory @@ -333,20 +333,20 @@ cg_found: brelse(bh); } - unlock_super (sb); + mutex_unlock(&sbi->s_lock); UFSD("allocating inode %lu\n", inode->i_ino); UFSD("EXIT\n"); return inode; fail_remove_inode: - unlock_super(sb); + mutex_unlock(&sbi->s_lock); clear_nlink(inode); iput(inode); UFSD("EXIT (FAILED): err %d\n", err); return ERR_PTR(err); failed: - unlock_super (sb); + mutex_unlock(&sbi->s_lock); make_bad_inode(inode); iput (inode); UFSD("EXIT (FAILED): err %d\n", err); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index f7cfecfe1cab..dc8e3a861d0f 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -699,7 +699,7 @@ static int ufs_sync_fs(struct super_block *sb, int wait) unsigned flags; lock_ufs(sb); - lock_super(sb); + mutex_lock(&UFS_SB(sb)->s_lock); UFSD("ENTER\n"); @@ -717,7 +717,7 @@ static int ufs_sync_fs(struct super_block *sb, int wait) ufs_put_cstotal(sb); UFSD("EXIT\n"); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return 0; @@ -805,6 +805,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) } #endif mutex_init(&sbi->mutex); + mutex_init(&sbi->s_lock); spin_lock_init(&sbi->work_lock); INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs); /* @@ -1280,7 +1281,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) unsigned flags; lock_ufs(sb); - lock_super(sb); + mutex_lock(&UFS_SB(sb)->s_lock); uspi = UFS_SB(sb)->s_uspi; flags = UFS_SB(sb)->s_flags; usb1 = ubh_get_usb_first(uspi); @@ -1294,7 +1295,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) new_mount_opt = 0; ufs_set_opt (new_mount_opt, ONERROR_LOCK); if (!ufs_parse_options (data, &new_mount_opt)) { - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return -EINVAL; } @@ -1302,14 +1303,14 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) new_mount_opt |= ufstype; } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { printk("ufstype can't be changed during remount\n"); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return -EINVAL; } if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { UFS_SB(sb)->s_mount_opt = new_mount_opt; - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return 0; } @@ -1334,7 +1335,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) #ifndef CONFIG_UFS_FS_WRITE printk("ufs was compiled with read-only support, " "can't be mounted as read-write\n"); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return -EINVAL; #else @@ -1344,13 +1345,13 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && ufstype != UFS_MOUNT_UFSTYPE_UFS2) { printk("this ufstype is read-only supported\n"); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return -EINVAL; } if (!ufs_read_cylinder_structures(sb)) { printk("failed during remounting\n"); - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return -EPERM; } @@ -1358,7 +1359,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) #endif } UFS_SB(sb)->s_mount_opt = new_mount_opt; - unlock_super(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); unlock_ufs(sb); return 0; } diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 343e6fc571e5..ff2c15ab81aa 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -24,6 +24,7 @@ struct ufs_sb_info { int work_queued; /* non-zero if the delayed work is queued */ struct delayed_work sync_work; /* FS sync delayed work */ spinlock_t work_lock; /* protects sync_work and work_queued */ + struct mutex s_lock; }; struct ufs_inode_info { diff --git a/fs/xattr.c b/fs/xattr.c index 1780f062dbaf..e164dddb8e96 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, if (!f.file) return error; dentry = f.file->f_path.dentry; - audit_inode(NULL, dentry); + audit_inode(NULL, dentry, 0); error = mnt_want_write_file(f.file); if (!error) { error = setxattr(dentry, name, value, size, flags); @@ -507,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name, if (!f.file) return error; - audit_inode(NULL, f.file->f_path.dentry); + audit_inode(NULL, f.file->f_path.dentry, 0); error = getxattr(f.file->f_path.dentry, name, value, size); fdput(f); return error; @@ -586,7 +586,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size) if (!f.file) return error; - audit_inode(NULL, f.file->f_path.dentry); + audit_inode(NULL, f.file->f_path.dentry, 0); error = listxattr(f.file->f_path.dentry, list, size); fdput(f); return error; @@ -655,7 +655,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) if (!f.file) return error; dentry = f.file->f_path.dentry; - audit_inode(NULL, dentry); + audit_inode(NULL, dentry, 0); error = mnt_want_write_file(f.file); if (!error) { error = removexattr(dentry, name); diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c index 42679223a0fd..8c6d1d70278c 100644 --- a/fs/xfs/xfs_export.c +++ b/fs/xfs/xfs_export.c @@ -189,6 +189,9 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid, struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; struct inode *inode = NULL; + if (fh_len < xfs_fileid_length(fileid_type)) + return NULL; + switch (fileid_type) { case FILEID_INO32_GEN_PARENT: inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino, diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index 96c5c249b086..9069694e70eb 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h @@ -21,7 +21,6 @@ enum alarmtimer_restart { #define ALARMTIMER_STATE_INACTIVE 0x00 #define ALARMTIMER_STATE_ENQUEUED 0x01 -#define ALARMTIMER_STATE_CALLBACK 0x02 /** * struct alarm - Alarm timer structure @@ -35,6 +34,7 @@ enum alarmtimer_restart { */ struct alarm { struct timerqueue_node node; + struct hrtimer timer; enum alarmtimer_restart (*function)(struct alarm *, ktime_t now); enum alarmtimer_type type; int state; @@ -43,39 +43,12 @@ struct alarm { void alarm_init(struct alarm *alarm, enum alarmtimer_type type, enum alarmtimer_restart (*function)(struct alarm *, ktime_t)); -void alarm_start(struct alarm *alarm, ktime_t start); +int alarm_start(struct alarm *alarm, ktime_t start); int alarm_try_to_cancel(struct alarm *alarm); int alarm_cancel(struct alarm *alarm); u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); -/* - * A alarmtimer is active, when it is enqueued into timerqueue or the - * callback function is running. - */ -static inline int alarmtimer_active(const struct alarm *timer) -{ - return timer->state != ALARMTIMER_STATE_INACTIVE; -} - -/* - * Helper function to check, whether the timer is on one of the queues - */ -static inline int alarmtimer_is_queued(struct alarm *timer) -{ - return timer->state & ALARMTIMER_STATE_ENQUEUED; -} - -/* - * Helper function to check, whether the timer is running the callback - * function - */ -static inline int alarmtimer_callback_running(struct alarm *timer) -{ - return timer->state & ALARMTIMER_STATE_CALLBACK; -} - - /* Provide way to access the rtc device being used by alarmtimers */ struct rtc_device *alarmtimer_get_rtcdev(void); diff --git a/include/linux/audit.h b/include/linux/audit.h index 2c83e5f7edb1..e5884f950b4b 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -452,6 +452,16 @@ struct audit_field { extern int __init audit_register_class(int class, unsigned *list); extern int audit_classify_syscall(int abi, unsigned syscall); extern int audit_classify_arch(int arch); + +/* audit_names->type values */ +#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ +#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */ +#define AUDIT_TYPE_PARENT 2 /* a parent audit record */ +#define AUDIT_TYPE_CHILD_DELETE 3 /* a child being deleted */ +#define AUDIT_TYPE_CHILD_CREATE 4 /* a child being created */ + +struct filename; + #ifdef CONFIG_AUDITSYSCALL /* These are defined in auditsc.c */ /* Public API */ @@ -461,11 +471,14 @@ extern void __audit_syscall_entry(int arch, int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3); extern void __audit_syscall_exit(int ret_success, long ret_value); -extern void __audit_getname(const char *name); -extern void audit_putname(const char *name); -extern void __audit_inode(const char *name, const struct dentry *dentry); -extern void __audit_inode_child(const struct dentry *dentry, - const struct inode *parent); +extern struct filename *__audit_reusename(const __user char *uptr); +extern void __audit_getname(struct filename *name); +extern void audit_putname(struct filename *name); +extern void __audit_inode(struct filename *name, const struct dentry *dentry, + unsigned int parent); +extern void __audit_inode_child(const struct inode *parent, + const struct dentry *dentry, + const unsigned char type); extern void __audit_seccomp(unsigned long syscall, long signr, int code); extern void __audit_ptrace(struct task_struct *t); @@ -495,19 +508,27 @@ static inline void audit_syscall_exit(void *pt_regs) __audit_syscall_exit(success, return_code); } } -static inline void audit_getname(const char *name) +static inline struct filename *audit_reusename(const __user char *name) +{ + if (unlikely(!audit_dummy_context())) + return __audit_reusename(name); + return NULL; +} +static inline void audit_getname(struct filename *name) { if (unlikely(!audit_dummy_context())) __audit_getname(name); } -static inline void audit_inode(const char *name, const struct dentry *dentry) { +static inline void audit_inode(struct filename *name, const struct dentry *dentry, + unsigned int parent) { if (unlikely(!audit_dummy_context())) - __audit_inode(name, dentry); + __audit_inode(name, dentry, parent); } -static inline void audit_inode_child(const struct dentry *dentry, - const struct inode *parent) { +static inline void audit_inode_child(const struct inode *parent, + const struct dentry *dentry, + const unsigned char type) { if (unlikely(!audit_dummy_context())) - __audit_inode_child(dentry, parent); + __audit_inode_child(parent, dentry, type); } void audit_core_dumps(long signr); @@ -651,19 +672,29 @@ static inline int audit_dummy_context(void) { return 1; } -static inline void audit_getname(const char *name) +static inline struct filename *audit_reusename(const __user char *name) +{ + return NULL; +} +static inline void audit_getname(struct filename *name) { } -static inline void audit_putname(const char *name) +static inline void audit_putname(struct filename *name) { } -static inline void __audit_inode(const char *name, const struct dentry *dentry) +static inline void __audit_inode(struct filename *name, + const struct dentry *dentry, + unsigned int parent) { } -static inline void __audit_inode_child(const struct dentry *dentry, - const struct inode *parent) +static inline void __audit_inode_child(const struct inode *parent, + const struct dentry *dentry, + const unsigned char type) { } -static inline void audit_inode(const char *name, const struct dentry *dentry) +static inline void audit_inode(struct filename *name, + const struct dentry *dentry, + unsigned int parent) { } -static inline void audit_inode_child(const struct dentry *dentry, - const struct inode *parent) +static inline void audit_inode_child(const struct inode *parent, + const struct dentry *dentry, + const unsigned char type) { } static inline void audit_core_dumps(long signr) { } diff --git a/include/linux/can/Kbuild b/include/linux/can/Kbuild index c62b7f1728f9..e69de29bb2d1 100644 --- a/include/linux/can/Kbuild +++ b/include/linux/can/Kbuild @@ -1,5 +0,0 @@ -header-y += raw.h -header-y += bcm.h -header-y += gw.h -header-y += error.h -header-y += netlink.h diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index fbe89e17124e..4dceaf8ae152 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -319,22 +319,6 @@ static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz) __clocksource_updatefreq_scale(cs, 1000, khz); } -#ifdef CONFIG_GENERIC_TIME_VSYSCALL -extern void -update_vsyscall(struct timespec *ts, struct timespec *wtm, - struct clocksource *c, u32 mult); -extern void update_vsyscall_tz(void); -#else -static inline void -update_vsyscall(struct timespec *ts, struct timespec *wtm, - struct clocksource *c, u32 mult) -{ -} - -static inline void update_vsyscall_tz(void) -{ -} -#endif extern void timekeeping_notify(struct clocksource *clock); diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h index 934bc34d5f99..412bc6c2b023 100644 --- a/include/linux/compiler-gcc4.h +++ b/include/linux/compiler-gcc4.h @@ -59,7 +59,7 @@ #if __GNUC_MINOR__ > 0 #define __compiletime_object_size(obj) __builtin_object_size(obj, 0) #endif -#if __GNUC_MINOR__ >= 4 && !defined(__CHECKER__) +#if __GNUC_MINOR__ >= 3 && !defined(__CHECKER__) #define __compiletime_warning(message) __attribute__((warning(message))) #define __compiletime_error(message) __attribute__((error(message))) #endif diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 20e5eac2ffd3..827cce7e33e3 100644 --- a/include/linux/dvb/version.h +++ b/include/linux/dvb/version.h @@ -24,6 +24,6 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 8 +#define DVB_API_VERSION_MINOR 9 #endif /*_DVBVERSION_H_*/ diff --git a/include/linux/fs.h b/include/linux/fs.h index 39f3e12ca752..65fbf571023f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1136,7 +1136,7 @@ static inline int file_check_writeable(struct file *filp) #if BITS_PER_LONG==32 #define MAX_LFS_FILESIZE (((loff_t)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) #elif BITS_PER_LONG==64 -#define MAX_LFS_FILESIZE ((loff_t)0x7fffffffffffffff) +#define MAX_LFS_FILESIZE ((loff_t)0x7fffffffffffffffLL) #endif #define FL_POSIX 1 @@ -1511,7 +1511,6 @@ struct super_block { unsigned long s_magic; struct dentry *s_root; struct rw_semaphore s_umount; - struct mutex s_lock; int s_count; atomic_t s_active; #ifdef CONFIG_SECURITY @@ -2080,7 +2079,7 @@ extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data); extern void kern_unmount(struct vfsmount *mnt); extern int may_umount_tree(struct vfsmount *); extern int may_umount(struct vfsmount *); -extern long do_mount(char *, char *, char *, unsigned long, void *); +extern long do_mount(const char *, const char *, const char *, unsigned long, void *); extern struct vfsmount *collect_mounts(struct path *); extern void drop_collected_mounts(struct vfsmount *); extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, @@ -2197,6 +2196,13 @@ static inline int break_lease(struct inode *inode, unsigned int mode) #endif /* CONFIG_FILE_LOCKING */ /* fs/open.c */ +struct audit_names; +struct filename { + const char *name; /* pointer to actual string */ + const __user char *uptr; /* original userland pointer */ + struct audit_names *aname; + bool separate; /* should "name" be freed? */ +}; extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, struct file *filp); @@ -2204,12 +2210,15 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len); extern long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode); +extern struct file *file_open_name(struct filename *, int, umode_t); extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int); extern struct file * dentry_open(const struct path *, int, const struct cred *); extern int filp_close(struct file *, fl_owner_t id); -extern char * getname(const char __user *); + +extern struct filename *getname(const char __user *); + enum { FILE_CREATED = 1, FILE_OPENED = 2 @@ -2229,13 +2238,14 @@ extern void __init vfs_caches_init(unsigned long); extern struct kmem_cache *names_cachep; -#define __getname_gfp(gfp) kmem_cache_alloc(names_cachep, (gfp)) -#define __getname() __getname_gfp(GFP_KERNEL) +extern void final_putname(struct filename *name); + +#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL) #define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) #ifndef CONFIG_AUDITSYSCALL -#define putname(name) __putname(name) +#define putname(name) final_putname(name) #else -extern void putname(const char *name); +extern void putname(struct filename *name); #endif #ifdef CONFIG_BLOCK diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index a6dfe6944564..0fbfb4646d1b 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -109,7 +109,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, if (source) fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); - audit_inode_child(moved, new_dir); + audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE); } /* @@ -155,7 +155,7 @@ static inline void fsnotify_inoderemove(struct inode *inode) */ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) { - audit_inode_child(dentry, inode); + audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); } @@ -168,7 +168,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) { fsnotify_link_count(inode); - audit_inode_child(new_dentry, dir); + audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0); } @@ -181,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) __u32 mask = (FS_CREATE | FS_ISDIR); struct inode *d_inode = dentry->d_inode; - audit_inode_child(dentry, inode); + audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); } diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h index 1364d62e2fbe..a3c3ecd59f08 100644 --- a/include/linux/i2c-algo-pca.h +++ b/include/linux/i2c-algo-pca.h @@ -62,6 +62,7 @@ struct i2c_algo_pca_data { * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000 * For PCA9665, use the frequency you want here. */ unsigned int i2c_clock; + unsigned int chip; }; int i2c_pca_add_bus(struct i2c_adapter *); diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc75bc74..df804ba73e0b 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,7 +34,6 @@ struct omap_i2c_bus_platform_data { u32 clkrate; u32 rev; u32 flags; - void (*set_mpu_wkup_lat)(struct device *dev, long set); }; #endif diff --git a/include/linux/i2c/i2c-rcar.h b/include/linux/i2c/i2c-rcar.h new file mode 100644 index 000000000000..496f5c2b23c9 --- /dev/null +++ b/include/linux/i2c/i2c-rcar.h @@ -0,0 +1,10 @@ +#ifndef __I2C_R_CAR_H__ +#define __I2C_R_CAR_H__ + +#include <linux/platform_device.h> + +struct i2c_rcar_platform_data { + u32 bus_speed; +}; + +#endif /* __I2C_R_CAR_H__ */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index e4dad4ddf085..3265f332998a 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -284,10 +284,16 @@ enum { IFLA_VXLAN_LEARNING, IFLA_VXLAN_AGEING, IFLA_VXLAN_LIMIT, + IFLA_VXLAN_PORT_RANGE, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) +struct ifla_vxlan_port_range { + __be16 low; + __be16 high; +}; + /* SR-IOV virtual function management section */ enum { diff --git a/include/linux/input.h b/include/linux/input.h index ba4874302939..15464ba6bf53 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1396,8 +1396,8 @@ struct input_handle; * @start: starts handler for given handle. This function is called by * input core right after connect() method and also when a process * that "grabbed" a device releases it - * @fops: file operations this driver implements - * @minor: beginning of range of 32 minors for devices this driver + * @legacy_minors: set to %true by drivers using legacy minor ranges + * @minor: beginning of range of 32 legacy minors for devices this driver * can provide * @name: name of the handler, to be shown in /proc/bus/input/handlers * @id_table: pointer to a table of input_device_ids this driver can @@ -1431,7 +1431,7 @@ struct input_handler { void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); - const struct file_operations *fops; + bool legacy_minors; int minor; const char *name; @@ -1499,6 +1499,10 @@ void input_reset_device(struct input_dev *); int __must_check input_register_handler(struct input_handler *); void input_unregister_handler(struct input_handler *); +int __must_check input_get_new_minor(int legacy_base, unsigned int legacy_num, + bool allow_dynamic); +void input_free_minor(unsigned int minor); + int input_handler_for_each_handle(struct input_handler *, void *data, int (*fn)(struct input_handle *, void *)); diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 05e3c2c7a8cf..6b87413da9d6 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -51,31 +51,17 @@ #define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \ + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN)) -#ifdef CLOCK_TICK_RATE /* LATCH is used in the interval timer and ftape setup. */ -# define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ +#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ -/* - * HZ is the requested value. However the CLOCK_TICK_RATE may not allow - * for exactly HZ. So SHIFTED_HZ is high res HZ ("<< 8" is for accuracy) - */ -# define SHIFTED_HZ (SH_DIV(CLOCK_TICK_RATE, LATCH, 8)) -#else -# define SHIFTED_HZ (HZ << 8) -#endif +extern int register_refined_jiffies(long clock_tick_rate); /* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ -#define TICK_NSEC (SH_DIV(1000000UL * 1000, SHIFTED_HZ, 8)) +#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) -/* - * TICK_USEC_TO_NSEC is the time between ticks in nsec assuming SHIFTED_HZ and - * a value TUSEC for TICK_USEC (can be set bij adjtimex) - */ -#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV(TUSEC * USER_HZ * 1000, SHIFTED_HZ, 8)) - /* some arch's have a small-data section that can be accessed register-relative * but that can only take up to, say, 4-byte variables. jiffies being part of * an 8-byte variable may not be correctly accessed unless we force the issue diff --git a/include/linux/lglock.h b/include/linux/lglock.h index f01e5f6d1f07..0d24e932db0b 100644 --- a/include/linux/lglock.h +++ b/include/linux/lglock.h @@ -32,20 +32,13 @@ #define br_write_lock(name) lg_global_lock(name) #define br_write_unlock(name) lg_global_unlock(name) -#define DEFINE_BRLOCK(name) DEFINE_LGLOCK(name) +#define DEFINE_BRLOCK(name) DEFINE_LGLOCK(name) +#define DEFINE_STATIC_BRLOCK(name) DEFINE_STATIC_LGLOCK(name) #ifdef CONFIG_DEBUG_LOCK_ALLOC #define LOCKDEP_INIT_MAP lockdep_init_map - -#define DEFINE_LGLOCK_LOCKDEP(name) \ - struct lock_class_key name##_lock_key; \ - struct lockdep_map name##_lock_dep_map; \ - EXPORT_SYMBOL(name##_lock_dep_map) - #else #define LOCKDEP_INIT_MAP(a, b, c, d) - -#define DEFINE_LGLOCK_LOCKDEP(name) #endif struct lglock { @@ -57,11 +50,15 @@ struct lglock { }; #define DEFINE_LGLOCK(name) \ - DEFINE_LGLOCK_LOCKDEP(name); \ - DEFINE_PER_CPU(arch_spinlock_t, name ## _lock) \ + static DEFINE_PER_CPU(arch_spinlock_t, name ## _lock) \ = __ARCH_SPIN_LOCK_UNLOCKED; \ struct lglock name = { .lock = &name ## _lock } +#define DEFINE_STATIC_LGLOCK(name) \ + static DEFINE_PER_CPU(arch_spinlock_t, name ## _lock) \ + = __ARCH_SPIN_LOCK_UNLOCKED; \ + static struct lglock name = { .lock = &name ## _lock } + void lg_lock_init(struct lglock *lg, char *name); void lg_local_lock(struct lglock *lg); void lg_local_unlock(struct lglock *lg); diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index fd0e6d53836e..11ddc7ffeba8 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -396,7 +396,7 @@ enum { }; struct sock; -#ifdef CONFIG_MEMCG_KMEM +#if defined(CONFIG_INET) && defined(CONFIG_MEMCG_KMEM) void sock_update_memcg(struct sock *sk); void sock_release_memcg(struct sock *sk); #else @@ -406,6 +406,6 @@ static inline void sock_update_memcg(struct sock *sk) static inline void sock_release_memcg(struct sock *sk) { } -#endif /* CONFIG_MEMCG_KMEM */ +#endif /* CONFIG_INET && CONFIG_MEMCG_KMEM */ #endif /* _LINUX_MEMCONTROL_H */ diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild index 5b7d84ac954a..e69de29bb2d1 100644 --- a/include/linux/nfsd/Kbuild +++ b/include/linux/nfsd/Kbuild @@ -1,5 +0,0 @@ -header-y += cld.h -header-y += debug.h -header-y += export.h -header-y += nfsfh.h -header-y += stats.h diff --git a/include/linux/nfsd/debug.h b/include/linux/nfsd/debug.h index ee4aa91788e7..19ef8375b577 100644 --- a/include/linux/nfsd/debug.h +++ b/include/linux/nfsd/debug.h @@ -5,44 +5,15 @@ * * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> */ - #ifndef LINUX_NFSD_DEBUG_H #define LINUX_NFSD_DEBUG_H -#include <linux/sunrpc/debug.h> +#include <uapi/linux/nfsd/debug.h> -/* - * Enable debugging for nfsd. - * Requires RPC_DEBUG. - */ -#ifdef RPC_DEBUG -# define NFSD_DEBUG 1 -#endif - -/* - * knfsd debug flags - */ -#define NFSDDBG_SOCK 0x0001 -#define NFSDDBG_FH 0x0002 -#define NFSDDBG_EXPORT 0x0004 -#define NFSDDBG_SVC 0x0008 -#define NFSDDBG_PROC 0x0010 -#define NFSDDBG_FILEOP 0x0020 -#define NFSDDBG_AUTH 0x0040 -#define NFSDDBG_REPCACHE 0x0080 -#define NFSDDBG_XDR 0x0100 -#define NFSDDBG_LOCKD 0x0200 -#define NFSDDBG_ALL 0x7FFF -#define NFSDDBG_NOCHANGE 0xFFFF - - -#ifdef __KERNEL__ # undef ifdebug # ifdef NFSD_DEBUG # define ifdebug(flag) if (nfsd_debug & NFSDDBG_##flag) # else # define ifdebug(flag) if (0) # endif -#endif /* __KERNEL__ */ - #endif /* LINUX_NFSD_DEBUG_H */ diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index e33f747b173c..24c139288db4 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -6,58 +6,11 @@ * * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> */ - #ifndef NFSD_EXPORT_H #define NFSD_EXPORT_H -# include <linux/types.h> -#ifdef __KERNEL__ # include <linux/nfsd/nfsfh.h> -#endif - -/* - * Important limits for the exports stuff. - */ -#define NFSCLNT_IDMAX 1024 -#define NFSCLNT_ADDRMAX 16 -#define NFSCLNT_KEYMAX 32 - -/* - * Export flags. - */ -#define NFSEXP_READONLY 0x0001 -#define NFSEXP_INSECURE_PORT 0x0002 -#define NFSEXP_ROOTSQUASH 0x0004 -#define NFSEXP_ALLSQUASH 0x0008 -#define NFSEXP_ASYNC 0x0010 -#define NFSEXP_GATHERED_WRITES 0x0020 -/* 40 80 100 currently unused */ -#define NFSEXP_NOHIDE 0x0200 -#define NFSEXP_NOSUBTREECHECK 0x0400 -#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ -#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */ -#define NFSEXP_FSID 0x2000 -#define NFSEXP_CROSSMOUNT 0x4000 -#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ -/* - * The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4 - * clients, and only to the single directory that is the root of the - * export; further lookup and readdir operations are treated as if every - * subdirectory was a mountpoint, and ignored if they are not themselves - * exported. This is used by nfsd and mountd to construct the NFSv4 - * pseudofilesystem, which provides access only to paths leading to each - * exported filesystem. - */ -#define NFSEXP_V4ROOT 0x10000 -/* All flags that we claim to support. (Note we don't support NOACL.) */ -#define NFSEXP_ALLFLAGS 0x17E3F - -/* The flags that may vary depending on security flavor: */ -#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ - | NFSEXP_ALLSQUASH \ - | NFSEXP_INSECURE_PORT) - -#ifdef __KERNEL__ +#include <uapi/linux/nfsd/export.h> /* * FS Locations @@ -154,7 +107,4 @@ static inline void exp_get(struct svc_export *exp) } struct svc_export * rqst_exp_find(struct svc_rqst *, int, u32 *); -#endif /* __KERNEL__ */ - #endif /* NFSD_EXPORT_H */ - diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index fa63048fecff..a93593f1fa4e 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -10,117 +10,11 @@ * * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */ - #ifndef _LINUX_NFSD_FH_H #define _LINUX_NFSD_FH_H -#include <linux/types.h> -#include <linux/nfs.h> -#include <linux/nfs2.h> -#include <linux/nfs3.h> -#include <linux/nfs4.h> -#ifdef __KERNEL__ # include <linux/sunrpc/svc.h> -#endif - -/* - * This is the old "dentry style" Linux NFSv2 file handle. - * - * The xino and xdev fields are currently used to transport the - * ino/dev of the exported inode. - */ -struct nfs_fhbase_old { - __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ - __u32 fb_ino; /* our inode number */ - __u32 fb_dirino; /* dir inode number, 0 for directories */ - __u32 fb_dev; /* our device */ - __u32 fb_xdev; - __u32 fb_xino; - __u32 fb_generation; -}; - -/* - * This is the new flexible, extensible style NFSv2/v3 file handle. - * by Neil Brown <neilb@cse.unsw.edu.au> - March 2000 - * - * The file handle starts with a sequence of four-byte words. - * The first word contains a version number (1) and three descriptor bytes - * that tell how the remaining 3 variable length fields should be handled. - * These three bytes are auth_type, fsid_type and fileid_type. - * - * All four-byte values are in host-byte-order. - * - * The auth_type field specifies how the filehandle can be authenticated - * This might allow a file to be confirmed to be in a writable part of a - * filetree without checking the path from it up to the root. - * Current values: - * 0 - No authentication. fb_auth is 0 bytes long - * Possible future values: - * 1 - 4 bytes taken from MD5 hash of the remainer of the file handle - * prefixed by a secret and with the important export flags. - * - * The fsid_type identifies how the filesystem (or export point) is - * encoded. - * Current values: - * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number - * NOTE: we cannot use the kdev_t device id value, because kdev_t.h - * says we mustn't. We must break it up and reassemble. - * 1 - 4 byte user specified identifier - * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED - * 3 - 4 byte device id, encoded for user-space, 4 byte inode number - * 4 - 4 byte inode number and 4 byte uuid - * 5 - 8 byte uuid - * 6 - 16 byte uuid - * 7 - 8 byte inode number and 16 byte uuid - * - * The fileid_type identified how the file within the filesystem is encoded. - * This is (will be) passed to, and set by, the underlying filesystem if it supports - * filehandle operations. The filesystem must not use the value '0' or '0xff' and may - * only use the values 1 and 2 as defined below: - * Current values: - * 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes. - * 1 - 32bit inode number, 32 bit generation number. - * 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number. - * - */ -struct nfs_fhbase_new { - __u8 fb_version; /* == 1, even => nfs_fhbase_old */ - __u8 fb_auth_type; - __u8 fb_fsid_type; - __u8 fb_fileid_type; - __u32 fb_auth[1]; -/* __u32 fb_fsid[0]; floating */ -/* __u32 fb_fileid[0]; floating */ -}; - -struct knfsd_fh { - unsigned int fh_size; /* significant for NFSv3. - * Points to the current size while building - * a new file handle - */ - union { - struct nfs_fhbase_old fh_old; - __u32 fh_pad[NFS4_FHSIZE/4]; - struct nfs_fhbase_new fh_new; - } fh_base; -}; - -#define ofh_dcookie fh_base.fh_old.fb_dcookie -#define ofh_ino fh_base.fh_old.fb_ino -#define ofh_dirino fh_base.fh_old.fb_dirino -#define ofh_dev fh_base.fh_old.fb_dev -#define ofh_xdev fh_base.fh_old.fb_xdev -#define ofh_xino fh_base.fh_old.fb_xino -#define ofh_generation fh_base.fh_old.fb_generation - -#define fh_version fh_base.fh_new.fb_version -#define fh_fsid_type fh_base.fh_new.fb_fsid_type -#define fh_auth_type fh_base.fh_new.fb_auth_type -#define fh_fileid_type fh_base.fh_new.fb_fileid_type -#define fh_auth fh_base.fh_new.fb_auth -#define fh_fsid fh_base.fh_new.fb_auth - -#ifdef __KERNEL__ +#include <uapi/linux/nfsd/nfsfh.h> static inline __u32 ino_t_to_u32(ino_t ino) { @@ -166,7 +60,4 @@ typedef struct svc_fh { } svc_fh; -#endif /* __KERNEL__ */ - - #endif /* _LINUX_NFSD_FH_H */ diff --git a/include/linux/nfsd/stats.h b/include/linux/nfsd/stats.h index 2693ef647df6..e75b2544ff12 100644 --- a/include/linux/nfsd/stats.h +++ b/include/linux/nfsd/stats.h @@ -5,16 +5,11 @@ * * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ - #ifndef LINUX_NFSD_STATS_H #define LINUX_NFSD_STATS_H -#include <linux/nfs4.h> - -/* thread usage wraps very million seconds (approx one fortnight) */ -#define NFSD_USAGE_WRAP (HZ*1000000) +#include <uapi/linux/nfsd/stats.h> -#ifdef __KERNEL__ struct nfsd_stats { unsigned int rchits; /* repcache hits */ @@ -47,5 +42,4 @@ extern struct svc_stat nfsd_svcstats; void nfsd_stat_init(void); void nfsd_stat_shutdown(void); -#endif /* __KERNEL__ */ #endif /* LINUX_NFSD_STATS_H */ diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 6ef49b803efb..8163107b94b4 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -26,32 +26,32 @@ extern struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); #else /* CONFIG_OF */ -int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) +static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) { return -ENOSYS; } -struct phy_device *of_phy_find_device(struct device_node *phy_np) +static inline struct phy_device *of_phy_find_device(struct device_node *phy_np) { return NULL; } -struct phy_device *of_phy_connect(struct net_device *dev, - struct device_node *phy_np, - void (*hndlr)(struct net_device *), - u32 flags, phy_interface_t iface) +static inline struct phy_device *of_phy_connect(struct net_device *dev, + struct device_node *phy_np, + void (*hndlr)(struct net_device *), + u32 flags, phy_interface_t iface) { return NULL; } -struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, - void (*hndlr)(struct net_device *), - phy_interface_t iface) +static inline struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, + void (*hndlr)(struct net_device *), + phy_interface_t iface) { return NULL; } -struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np) +static inline struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np) { return NULL; } diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h index eed27f4f4c3e..be655e4a2a75 100644 --- a/include/linux/pageblock-flags.h +++ b/include/linux/pageblock-flags.h @@ -71,13 +71,13 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags, #ifdef CONFIG_COMPACTION #define get_pageblock_skip(page) \ get_pageblock_flags_group(page, PB_migrate_skip, \ - PB_migrate_skip + 1) + PB_migrate_skip) #define clear_pageblock_skip(page) \ set_pageblock_flags_group(page, 0, PB_migrate_skip, \ - PB_migrate_skip + 1) + PB_migrate_skip) #define set_pageblock_skip(page) \ set_pageblock_flags_group(page, 1, PB_migrate_skip, \ - PB_migrate_skip + 1) + PB_migrate_skip) #endif /* CONFIG_COMPACTION */ #define get_pageblock_flags(page) \ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 599afc4bb67e..b4166cdfa7a2 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1110,7 +1110,7 @@ struct perf_cpu_context { int exclusive; struct list_head rotation_list; int jiffies_interval; - struct pmu *active_pmu; + struct pmu *unique_pmu; struct perf_cgroup *cgrp; }; diff --git a/include/linux/platform_data/i2c-nomadik.h b/include/linux/platform_data/i2c-nomadik.h index c2303c3e4803..3a8be9cdc95c 100644 --- a/include/linux/platform_data/i2c-nomadik.h +++ b/include/linux/platform_data/i2c-nomadik.h @@ -28,7 +28,7 @@ enum i2c_freq_mode { * @sm: speed mode */ struct nmk_i2c_controller { - unsigned long clk_freq; + u32 clk_freq; unsigned short slsu; unsigned char tft; unsigned char rft; diff --git a/include/linux/platform_data/mipi-csis.h b/include/linux/platform_data/mipi-csis.h index c45b1e8d4c2e..bf34e17cee7f 100644 --- a/include/linux/platform_data/mipi-csis.h +++ b/include/linux/platform_data/mipi-csis.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. * - * S5P series MIPI CSI slave device support + * Samsung S5P/Exynos SoC series MIPI CSIS device 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,33 +11,27 @@ #ifndef __PLAT_SAMSUNG_MIPI_CSIS_H_ #define __PLAT_SAMSUNG_MIPI_CSIS_H_ __FILE__ -struct platform_device; - /** * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver - * @clk_rate: bus clock frequency - * @lanes: number of data lanes used - * @alignment: data alignment in bits - * @hs_settle: HS-RX settle time - * @fixed_phy_vdd: false to enable external D-PHY regulator management in the - * driver or true in case this regulator has no enable function - * @phy_enable: pointer to a callback controlling D-PHY enable/reset + * @clk_rate: bus clock frequency + * @wclk_source: CSI wrapper clock selection: 0 - bus clock, 1 - ext. SCLK_CAM + * @lanes: number of data lanes used + * @hs_settle: HS-RX settle time */ struct s5p_platform_mipi_csis { unsigned long clk_rate; + u8 wclk_source; u8 lanes; - u8 alignment; u8 hs_settle; - bool fixed_phy_vdd; - int (*phy_enable)(struct platform_device *pdev, bool on); }; /** * s5p_csis_phy_enable - global MIPI-CSI receiver D-PHY control - * @pdev: MIPI-CSIS platform device - * @on: true to enable D-PHY and deassert its reset - * false to disable D-PHY + * @id: MIPI-CSIS harware instance index (0...1) + * @on: true to enable D-PHY and deassert its reset + * false to disable D-PHY + * @return: 0 on success, or negative error code on failure */ -int s5p_csis_phy_enable(struct platform_device *pdev, bool on); +int s5p_csis_phy_enable(int id, bool on); #endif /* __PLAT_SAMSUNG_MIPI_CSIS_H_ */ diff --git a/include/linux/rio.h b/include/linux/rio.h index d2dff22cf681..4187da511006 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -63,7 +63,7 @@ * * 0 RapidIO inbound doorbells * 1 RapidIO inbound mailboxes - * 1 RapidIO outbound mailboxes + * 2 RapidIO outbound mailboxes */ #define RIO_DOORBELL_RESOURCE 0 #define RIO_INB_MBOX_RESOURCE 1 @@ -266,7 +266,6 @@ struct rio_mport { struct rio_id_table { u16 start; /* logical minimal id */ - u16 next; /* hint for find */ u32 max; /* max number of IDs in table */ spinlock_t lock; unsigned long *table; diff --git a/include/linux/security.h b/include/linux/security.h index 5b50c4e1a7c2..05e88bdcf7d9 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1411,8 +1411,8 @@ struct security_operations { int (*sb_kern_mount) (struct super_block *sb, int flags, void *data); int (*sb_show_options) (struct seq_file *m, struct super_block *sb); int (*sb_statfs) (struct dentry *dentry); - int (*sb_mount) (char *dev_name, struct path *path, - char *type, unsigned long flags, void *data); + int (*sb_mount) (const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data); int (*sb_umount) (struct vfsmount *mnt, int flags); int (*sb_pivotroot) (struct path *old_path, struct path *new_path); @@ -1694,8 +1694,8 @@ int security_sb_remount(struct super_block *sb, void *data); int security_sb_kern_mount(struct super_block *sb, int flags, void *data); int security_sb_show_options(struct seq_file *m, struct super_block *sb); int security_sb_statfs(struct dentry *dentry); -int security_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data); +int security_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data); int security_sb_umount(struct vfsmount *mnt, int flags); int security_sb_pivotroot(struct path *old_path, struct path *new_path); int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts); @@ -1964,8 +1964,8 @@ static inline int security_sb_statfs(struct dentry *dentry) return 0; } -static inline int security_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, +static inline int security_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return 0; diff --git a/include/linux/sunrpc/Kbuild b/include/linux/sunrpc/Kbuild index 98df21164a86..e69de29bb2d1 100644 --- a/include/linux/sunrpc/Kbuild +++ b/include/linux/sunrpc/Kbuild @@ -1 +0,0 @@ -header-y += debug.h diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index a76cc20d98ce..9385bd74c860 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -5,28 +5,11 @@ * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ - #ifndef _LINUX_SUNRPC_DEBUG_H_ #define _LINUX_SUNRPC_DEBUG_H_ -/* - * RPC debug facilities - */ -#define RPCDBG_XPRT 0x0001 -#define RPCDBG_CALL 0x0002 -#define RPCDBG_DEBUG 0x0004 -#define RPCDBG_NFS 0x0008 -#define RPCDBG_AUTH 0x0010 -#define RPCDBG_BIND 0x0020 -#define RPCDBG_SCHED 0x0040 -#define RPCDBG_TRANS 0x0080 -#define RPCDBG_SVCXPRT 0x0100 -#define RPCDBG_SVCDSP 0x0200 -#define RPCDBG_MISC 0x0400 -#define RPCDBG_CACHE 0x0800 -#define RPCDBG_ALL 0x7fff +#include <uapi/linux/sunrpc/debug.h> -#ifdef __KERNEL__ /* * Enable RPC debugging/profiling. @@ -87,24 +70,4 @@ void rpc_register_sysctl(void); void rpc_unregister_sysctl(void); #endif -#endif /* __KERNEL__ */ - -/* - * Declarations for the sysctl debug interface, which allows to read or - * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc - * module currently registers its sysctl table dynamically, the sysctl path - * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>. - */ - -enum { - CTL_RPCDEBUG = 1, - CTL_NFSDEBUG, - CTL_NFSDDEBUG, - CTL_NLMDEBUG, - CTL_SLOTTABLE_UDP, - CTL_SLOTTABLE_TCP, - CTL_MIN_RESVPORT, - CTL_MAX_RESVPORT, -}; - #endif /* _LINUX_SUNRPC_DEBUG_H_ */ diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index b3f64b12f141..b05963f09ebf 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -114,7 +114,6 @@ void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, int svc_create_xprt(struct svc_serv *, const char *, struct net *, const int, const unsigned short, int); void svc_xprt_enqueue(struct svc_xprt *xprt); -void svc_xprt_received(struct svc_xprt *); void svc_xprt_put(struct svc_xprt *xprt); void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); void svc_close_xprt(struct svc_xprt *xprt); @@ -124,6 +123,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, struct net *net, const sa_family_t af, const unsigned short port); int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); +void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt); static inline void svc_xprt_get(struct svc_xprt *xprt) { @@ -166,8 +166,7 @@ static inline size_t svc_addr_len(const struct sockaddr *sa) case AF_INET6: return sizeof(struct sockaddr_in6); } - - return 0; + BUG(); } static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index cb4ac69e1f33..92ad02f0dcc0 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -39,9 +39,6 @@ int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); -int svc_sock_names(struct svc_serv *serv, char *buf, - const size_t buflen, - const char *toclose); int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, const size_t len); void svc_init_xprt_sock(void); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 19439c75c5b2..727f0cd73921 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -827,7 +827,15 @@ asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, const char __user *pathname); asmlinkage long sys_syncfs(int fd); +#ifndef CONFIG_GENERIC_KERNEL_EXECVE int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); +#else +#define kernel_execve(filename, argv, envp) \ + do_execve(filename, \ + (const char __user *const __user *)argv, \ + (const char __user *const __user *)envp, \ + current_pt_regs()) +#endif asmlinkage long sys_perf_event_open( diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h new file mode 100644 index 000000000000..e1d558e237ec --- /dev/null +++ b/include/linux/timekeeper_internal.h @@ -0,0 +1,108 @@ +/* + * You SHOULD NOT be including this unless you're vsyscall + * handling code or timekeeping internal code! + */ + +#ifndef _LINUX_TIMEKEEPER_INTERNAL_H +#define _LINUX_TIMEKEEPER_INTERNAL_H + +#include <linux/clocksource.h> +#include <linux/jiffies.h> +#include <linux/time.h> + +/* Structure holding internal timekeeping values. */ +struct timekeeper { + /* Current clocksource used for timekeeping. */ + struct clocksource *clock; + /* NTP adjusted clock multiplier */ + u32 mult; + /* The shift value of the current clocksource. */ + u32 shift; + /* Number of clock cycles in one NTP interval. */ + cycle_t cycle_interval; + /* Number of clock shifted nano seconds in one NTP interval. */ + u64 xtime_interval; + /* shifted nano seconds left over when rounding cycle_interval */ + s64 xtime_remainder; + /* Raw nano seconds accumulated per NTP interval. */ + u32 raw_interval; + + /* Current CLOCK_REALTIME time in seconds */ + u64 xtime_sec; + /* Clock shifted nano seconds */ + u64 xtime_nsec; + + /* Difference between accumulated time and NTP time in ntp + * shifted nano seconds. */ + s64 ntp_error; + /* Shift conversion between clock shifted nano seconds and + * ntp shifted nano seconds. */ + u32 ntp_error_shift; + + /* + * wall_to_monotonic is what we need to add to xtime (or xtime corrected + * for sub jiffie times) to get to monotonic time. Monotonic is pegged + * at zero at system boot time, so wall_to_monotonic will be negative, + * however, we will ALWAYS keep the tv_nsec part positive so we can use + * the usual normalization. + * + * wall_to_monotonic is moved after resume from suspend for the + * monotonic time not to jump. We need to add total_sleep_time to + * wall_to_monotonic to get the real boot based time offset. + * + * - wall_to_monotonic is no longer the boot time, getboottime must be + * used instead. + */ + struct timespec wall_to_monotonic; + /* Offset clock monotonic -> clock realtime */ + ktime_t offs_real; + /* time spent in suspend */ + struct timespec total_sleep_time; + /* Offset clock monotonic -> clock boottime */ + ktime_t offs_boot; + /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ + struct timespec raw_time; + /* Seqlock for all timekeeper values */ + seqlock_t lock; +}; + +static inline struct timespec tk_xtime(struct timekeeper *tk) +{ + struct timespec ts; + + ts.tv_sec = tk->xtime_sec; + ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); + return ts; +} + + +#ifdef CONFIG_GENERIC_TIME_VSYSCALL + +extern void update_vsyscall(struct timekeeper *tk); +extern void update_vsyscall_tz(void); + +#elif defined(CONFIG_GENERIC_TIME_VSYSCALL_OLD) + +extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm, + struct clocksource *c, u32 mult); +extern void update_vsyscall_tz(void); + +static inline void update_vsyscall(struct timekeeper *tk) +{ + struct timespec xt; + + xt = tk_xtime(tk); + update_vsyscall_old(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); +} + +#else + +static inline void update_vsyscall(struct timekeeper *tk) +{ +} +static inline void update_vsyscall_tz(void) +{ +} +#endif + +#endif /* _LINUX_TIMEKEEPER_INTERNAL_H */ diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index f87cf622317f..ddbbb7de894b 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -68,6 +68,7 @@ struct usbnet { # define EVENT_RX_PAUSED 5 # define EVENT_DEV_ASLEEP 6 # define EVENT_DEV_OPEN 7 +# define EVENT_DEVICE_REPORT_IDLE 8 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) @@ -160,6 +161,7 @@ extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *); extern int usbnet_suspend(struct usb_interface *, pm_message_t); extern int usbnet_resume(struct usb_interface *); extern void usbnet_disconnect(struct usb_interface *); +extern void usbnet_device_suggests_idle(struct usbnet *dev); /* Drivers that reuse some of the standard USB CDC infrastructure diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h index 421d24c7f686..f56c945cecd4 100644 --- a/include/linux/v4l2-controls.h +++ b/include/linux/v4l2-controls.h @@ -349,6 +349,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) #define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) +#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225) #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) @@ -439,6 +440,46 @@ enum v4l2_mpeg_video_h264_vui_sar_idc { V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 = 16, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED = 17, }; +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING (V4L2_CID_MPEG_BASE+368) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0 (V4L2_CID_MPEG_BASE+369) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE (V4L2_CID_MPEG_BASE+370) +enum v4l2_mpeg_video_h264_sei_fp_arrangement_type { + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD = 0, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN = 1, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW = 2, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE = 3, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM = 4, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL = 5, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO (V4L2_CID_MPEG_BASE+371) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE (V4L2_CID_MPEG_BASE+372) +enum v4l2_mpeg_video_h264_fmo_map_type { + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES = 0, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES = 1, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER = 2, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT = 3, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN = 4, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN = 5, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT = 6, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP (V4L2_CID_MPEG_BASE+373) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION (V4L2_CID_MPEG_BASE+374) +enum v4l2_mpeg_video_h264_fmo_change_dir { + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT = 0, + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT = 1, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE (V4L2_CID_MPEG_BASE+375) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH (V4L2_CID_MPEG_BASE+376) +#define V4L2_CID_MPEG_VIDEO_H264_ASO (V4L2_CID_MPEG_BASE+377) +#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER (V4L2_CID_MPEG_BASE+378) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING (V4L2_CID_MPEG_BASE+379) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE (V4L2_CID_MPEG_BASE+380) +enum v4l2_mpeg_video_h264_hierarchical_coding_type { + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B = 0, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P = 1, +}; +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER (V4L2_CID_MPEG_BASE+381) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP (V4L2_CID_MPEG_BASE+382) #define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) #define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) #define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) @@ -757,5 +798,6 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1) #define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2) +#define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) #endif diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h index 5ea7f753a348..7d64e0e1a18b 100644 --- a/include/linux/v4l2-mediabus.h +++ b/include/linux/v4l2-mediabus.h @@ -92,6 +92,11 @@ enum v4l2_mbus_pixelcode { /* JPEG compressed formats - next is 0x4002 */ V4L2_MBUS_FMT_JPEG_1X8 = 0x4001, + + /* Vendor specific formats - next is 0x5002 */ + + /* S5C73M3 sensor specific interleaved UYVY and JPEG */ + V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 = 0x5001, }; /** diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 61395ef85a00..873adbe82988 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -366,7 +366,9 @@ struct v4l2_pix_format { /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ +#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 macroblocks */ /* three non contiguous planes - Y, Cb, Cr */ #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ @@ -403,6 +405,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ #define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ #define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */ +#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */ #define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3') /* H263 */ #define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES */ #define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES */ @@ -410,6 +413,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid */ #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */ #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ +#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ @@ -437,6 +441,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ #define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ #define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ +#define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */ /* * F O R M A T E N U M E R A T I O N diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h index dc8d305b0e05..d6b4440387b7 100644 --- a/include/linux/virtio_scsi.h +++ b/include/linux/virtio_scsi.h @@ -72,6 +72,7 @@ struct virtio_scsi_config { /* Feature Bits */ #define VIRTIO_SCSI_F_INOUT 0 #define VIRTIO_SCSI_F_HOTPLUG 1 +#define VIRTIO_SCSI_F_CHANGE 2 /* Response codes */ #define VIRTIO_SCSI_S_OK 0 @@ -108,6 +109,7 @@ struct virtio_scsi_config { #define VIRTIO_SCSI_T_NO_EVENT 0 #define VIRTIO_SCSI_T_TRANSPORT_RESET 1 #define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 +#define VIRTIO_SCSI_T_PARAM_CHANGE 3 /* Reasons of transport reset event */ #define VIRTIO_SCSI_EVT_RESET_HARD 0 diff --git a/include/linux/wimax/Kbuild b/include/linux/wimax/Kbuild index 3cb4f269bb09..e69de29bb2d1 100644 --- a/include/linux/wimax/Kbuild +++ b/include/linux/wimax/Kbuild @@ -1 +0,0 @@ -header-y += i2400m.h diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 8bc1b3c0e679..a7ca4884c46c 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -35,7 +35,7 @@ struct osd_config_info { struct vpbe_output { struct v4l2_output output; /* - * If output capabilities include dv_preset, list supported presets + * If output capabilities include dv_timings, list supported timings * below */ char *subdev_name; @@ -120,16 +120,16 @@ struct vpbe_device_ops { unsigned int (*get_output)(struct vpbe_device *vpbe_dev); /* Set DV preset at current output */ - int (*s_dv_preset)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset); + int (*s_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings); /* Get DV presets supported at the output */ - int (*g_dv_preset)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset); + int (*g_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings); /* Enumerate the DV Presets supported at the output */ - int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_enum_preset *preset_info); + int (*enum_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_enum_dv_timings *timings_info); /* Set std at the output */ int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h index 727f55170e41..9b85396514be 100644 --- a/include/media/davinci/vpbe_types.h +++ b/include/media/davinci/vpbe_types.h @@ -32,11 +32,6 @@ enum vpbe_enc_timings_type { VPBE_ENC_TIMINGS_INVALID = 0x8, }; -union vpbe_timings { - v4l2_std_id std_id; - unsigned int dv_preset; -}; - /* * struct vpbe_enc_mode_info * @name: ptr to name string of the standard, "NTSC", "PAL" etc @@ -73,7 +68,8 @@ union vpbe_timings { struct vpbe_enc_mode_info { unsigned char *name; enum vpbe_enc_timings_type timings_type; - union vpbe_timings timings; + v4l2_std_id std_id; + struct v4l2_dv_timings dv_timings; unsigned int interlaced; unsigned int xres; unsigned int yres; diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h index 6b57334f4029..cc78c2eb16da 100644 --- a/include/media/davinci/vpbe_venc.h +++ b/include/media/davinci/vpbe_venc.h @@ -32,7 +32,7 @@ struct venc_platform_data { int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type, int field); int (*setup_clock)(enum vpbe_enc_timings_type type, - unsigned int mode); + unsigned int pixclock); int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode); /* Number of LCD outputs supported */ int num_lcd_outputs; diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h index d8f6ab1943e4..3882e0675ccf 100644 --- a/include/media/davinci/vpif_types.h +++ b/include/media/davinci/vpif_types.h @@ -20,6 +20,7 @@ #include <linux/i2c.h> #define VPIF_CAPTURE_MAX_CHANNELS 2 +#define VPIF_DISPLAY_MAX_CHANNELS 2 enum vpif_if_type { VPIF_IF_BT656, @@ -37,29 +38,38 @@ struct vpif_interface { struct vpif_subdev_info { const char *name; struct i2c_board_info board_info; - u32 input; - u32 output; - unsigned can_route:1; - struct vpif_interface vpif_if; +}; + +struct vpif_output { + struct v4l2_output output; + const char *subdev_name; + u32 input_route; + u32 output_route; +}; + +struct vpif_display_chan_config { + const struct vpif_output *outputs; + int output_count; + bool clip_en; }; struct vpif_display_config { int (*set_clock)(int, int); struct vpif_subdev_info *subdevinfo; int subdev_count; - const char **output; - int output_count; + struct vpif_display_chan_config chan_config[VPIF_DISPLAY_MAX_CHANNELS]; const char *card_name; - bool ch2_clip_en; - bool ch3_clip_en; }; struct vpif_input { struct v4l2_input input; const char *subdev_name; + u32 input_route; + u32 output_route; }; struct vpif_capture_chan_config { + struct vpif_interface vpif_if; const struct vpif_input *inputs; int input_count; }; diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 09421a611d73..eaea62a382f8 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -30,7 +30,6 @@ struct i2c_board_info; * @board_info: pointer to I2C subdevice's board info * @clk_frequency: frequency of the clock the host interface provides to sensor * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc. - * @csi_data_align: MIPI-CSI interface data alignment in bits * @i2c_bus_num: i2c control bus id the sensor is attached to * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU) * @clk_id: index of the SoC peripheral clock for sensors @@ -40,7 +39,6 @@ struct s5p_fimc_isp_info { struct i2c_board_info *board_info; unsigned long clk_frequency; enum cam_bus_type bus_type; - u16 csi_data_align; u16 i2c_bus_num; u16 mux_id; u16 flags; diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 801adb466bd2..96509119f28f 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -351,6 +351,29 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 mask, s32 def); +/** v4l2_ctrl_new_std_menu_items() - Create a new standard V4L2 menu control + * with driver specific menu. + * @hdl: The control handler. + * @ops: The control ops. + * @id: The control ID. + * @max: The control's maximum value. + * @mask: The control's skip mask for menu controls. This makes it + * easy to skip menu items that are not valid. If bit X is set, + * then menu item X is skipped. Of course, this only works for + * menus with <= 32 menu items. There are no menus that come + * close to that number, so this is OK. Should we ever need more, + * then this will have to be extended to a u64 or a bit array. + * @def: The control's default value. + * @qmenu: The new menu. + * + * Same as v4l2_ctrl_new_std_menu(), but @qmenu will be the driver specific + * menu of this control. + * + */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 mask, s32 def, const char * const *qmenu); + /** v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control. * @hdl: The control handler. * @ops: The control ops. diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 2ecd7377153b..b137a5e1151a 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -21,6 +21,7 @@ #ifndef _V4L2_SUBDEV_H #define _V4L2_SUBDEV_H +#include <linux/types.h> #include <linux/v4l2-subdev.h> #include <media/media-entity.h> #include <media/v4l2-common.h> @@ -45,6 +46,7 @@ struct v4l2_fh; struct v4l2_subdev; struct v4l2_subdev_fh; struct tuner_setup; +struct v4l2_mbus_frame_desc; /* decode_vbi_line */ struct v4l2_decode_vbi_line { @@ -226,6 +228,36 @@ struct v4l2_subdev_audio_ops { int (*s_stream)(struct v4l2_subdev *sd, int enable); }; +/* Indicates the @length field specifies maximum data length. */ +#define V4L2_MBUS_FRAME_DESC_FL_LEN_MAX (1U << 0) +/* Indicates user defined data format, i.e. non standard frame format. */ +#define V4L2_MBUS_FRAME_DESC_FL_BLOB (1U << 1) + +/** + * struct v4l2_mbus_frame_desc_entry - media bus frame description structure + * @flags: V4L2_MBUS_FRAME_DESC_FL_* flags + * @pixelcode: media bus pixel code, valid if FRAME_DESC_FL_BLOB is not set + * @length: number of octets per frame, valid for compressed or unspecified + * formats + */ +struct v4l2_mbus_frame_desc_entry { + u16 flags; + u32 pixelcode; + u32 length; +}; + +#define V4L2_FRAME_DESC_ENTRY_MAX 4 + +/** + * struct v4l2_mbus_frame_desc - media bus data frame description + * @entry: frame descriptors array + * @num_entries: number of entries in @entry array + */ +struct v4l2_mbus_frame_desc { + struct v4l2_mbus_frame_desc_entry entry[V4L2_FRAME_DESC_ENTRY_MAX]; + unsigned short num_entries; +}; + /* s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by video input devices. @@ -274,6 +306,10 @@ struct v4l2_subdev_audio_ops { s_mbus_config: set a certain mediabus configuration. This operation is added for compatibility with soc-camera drivers and should not be used by new software. + + s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev + can adjust @size to a lower value and must not write more data to the + buffer starting at @data than the original value of @size. */ struct v4l2_subdev_video_ops { int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); @@ -327,6 +363,8 @@ struct v4l2_subdev_video_ops { struct v4l2_mbus_config *cfg); int (*s_mbus_config)(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg); + int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, + unsigned int *size); }; /* @@ -455,6 +493,12 @@ struct v4l2_subdev_ir_ops { struct v4l2_subdev_ir_parameters *params); }; +/** + * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations + * @get_frame_desc: get the current low level media bus frame parameters. + * @get_frame_desc: set the low level media bus frame parameters, @fd array + * may be adjusted by the subdev driver to device capabilities. + */ struct v4l2_subdev_pad_ops { int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code); @@ -483,6 +527,10 @@ struct v4l2_subdev_pad_ops { struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt); #endif /* CONFIG_MEDIA_CONTROLLER */ + int (*get_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd); + int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd); }; struct v4l2_subdev_ops { diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 0d7d67e96d43..9c8702942b61 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h @@ -127,6 +127,9 @@ struct fcp_txrdy { * * All response frames will always contain the fcp_resp template. Some * will also include the fcp_resp_len template. + * + * From Table 23, the FCP_RSP_INFO can either be 4 bytes or 8 bytes, both + * are valid length. */ struct fcp_resp { __u8 _fr_resvd[8]; /* reserved */ @@ -156,6 +159,9 @@ struct fcp_resp_rsp_info { __u8 _fr_resvd2[4]; /* reserved */ }; +#define FCP_RESP_RSP_INFO_LEN4 4 /* without reserved field */ +#define FCP_RESP_RSP_INFO_LEN8 8 /* with reserved field */ + struct fcp_resp_with_ext { struct fcp_resp resp; struct fcp_resp_ext ext; diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 22b07cc99808..8742d853a3b8 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -327,7 +327,6 @@ struct fcoe_percpu_s { * @lport: The associated local port * @fcoe_pending_queue: The pending Rx queue of skbs * @fcoe_pending_queue_active: Indicates if the pending queue is active - * @priority: Packet priority (DCB) * @max_queue_depth: Max queue depth of pending queue * @min_queue_depth: Min queue depth of pending queue * @timer: The queue timer @@ -343,7 +342,6 @@ struct fcoe_port { struct fc_lport *lport; struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; - u8 priority; u32 max_queue_depth; u32 min_queue_depth; struct timer_list timer; diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index ac06cc595890..de5f5d8f1f8a 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -132,18 +132,10 @@ struct scsi_cmnd { unsigned char tag; /* SCSI-II queued command tag */ }; +/* make sure not to use it with REQ_TYPE_BLOCK_PC commands */ static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) { - struct scsi_driver **sdp; - - if (!cmd->request->rq_disk) - return NULL; - - sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data; - if (!sdp) - return NULL; - - return *sdp; + return *(struct scsi_driver **)cmd->request->rq_disk->private_data; } extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); diff --git a/include/uapi/linux/can/Kbuild b/include/uapi/linux/can/Kbuild index aafaa5aa54d4..21c91bf25a29 100644 --- a/include/uapi/linux/can/Kbuild +++ b/include/uapi/linux/can/Kbuild @@ -1 +1,6 @@ # UAPI Header export list +header-y += bcm.h +header-y += error.h +header-y += gw.h +header-y += netlink.h +header-y += raw.h diff --git a/include/linux/can/bcm.h b/include/uapi/linux/can/bcm.h index 3ebe387fea4d..3ebe387fea4d 100644 --- a/include/linux/can/bcm.h +++ b/include/uapi/linux/can/bcm.h diff --git a/include/linux/can/error.h b/include/uapi/linux/can/error.h index 7b7148bded71..7b7148bded71 100644 --- a/include/linux/can/error.h +++ b/include/uapi/linux/can/error.h diff --git a/include/linux/can/gw.h b/include/uapi/linux/can/gw.h index 8e1db18c3cb6..8e1db18c3cb6 100644 --- a/include/linux/can/gw.h +++ b/include/uapi/linux/can/gw.h diff --git a/include/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index 14966ddb7df1..14966ddb7df1 100644 --- a/include/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h diff --git a/include/linux/can/raw.h b/include/uapi/linux/can/raw.h index a814062b0719..a814062b0719 100644 --- a/include/linux/can/raw.h +++ b/include/uapi/linux/can/raw.h diff --git a/include/uapi/linux/nfsd/Kbuild b/include/uapi/linux/nfsd/Kbuild index aafaa5aa54d4..c11bc404053c 100644 --- a/include/uapi/linux/nfsd/Kbuild +++ b/include/uapi/linux/nfsd/Kbuild @@ -1 +1,6 @@ # UAPI Header export list +header-y += cld.h +header-y += debug.h +header-y += export.h +header-y += nfsfh.h +header-y += stats.h diff --git a/include/linux/nfsd/cld.h b/include/uapi/linux/nfsd/cld.h index f14a9ab06f1f..f14a9ab06f1f 100644 --- a/include/linux/nfsd/cld.h +++ b/include/uapi/linux/nfsd/cld.h diff --git a/include/uapi/linux/nfsd/debug.h b/include/uapi/linux/nfsd/debug.h new file mode 100644 index 000000000000..a6f453c740b8 --- /dev/null +++ b/include/uapi/linux/nfsd/debug.h @@ -0,0 +1,40 @@ +/* + * linux/include/linux/nfsd/debug.h + * + * Debugging-related stuff for nfsd + * + * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _UAPILINUX_NFSD_DEBUG_H +#define _UAPILINUX_NFSD_DEBUG_H + +#include <linux/sunrpc/debug.h> + +/* + * Enable debugging for nfsd. + * Requires RPC_DEBUG. + */ +#ifdef RPC_DEBUG +# define NFSD_DEBUG 1 +#endif + +/* + * knfsd debug flags + */ +#define NFSDDBG_SOCK 0x0001 +#define NFSDDBG_FH 0x0002 +#define NFSDDBG_EXPORT 0x0004 +#define NFSDDBG_SVC 0x0008 +#define NFSDDBG_PROC 0x0010 +#define NFSDDBG_FILEOP 0x0020 +#define NFSDDBG_AUTH 0x0040 +#define NFSDDBG_REPCACHE 0x0080 +#define NFSDDBG_XDR 0x0100 +#define NFSDDBG_LOCKD 0x0200 +#define NFSDDBG_ALL 0x7FFF +#define NFSDDBG_NOCHANGE 0xFFFF + + + +#endif /* _UAPILINUX_NFSD_DEBUG_H */ diff --git a/include/uapi/linux/nfsd/export.h b/include/uapi/linux/nfsd/export.h new file mode 100644 index 000000000000..cf47c313794e --- /dev/null +++ b/include/uapi/linux/nfsd/export.h @@ -0,0 +1,58 @@ +/* + * include/linux/nfsd/export.h + * + * Public declarations for NFS exports. The definitions for the + * syscall interface are in nfsctl.h + * + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _UAPINFSD_EXPORT_H +#define _UAPINFSD_EXPORT_H + +# include <linux/types.h> + +/* + * Important limits for the exports stuff. + */ +#define NFSCLNT_IDMAX 1024 +#define NFSCLNT_ADDRMAX 16 +#define NFSCLNT_KEYMAX 32 + +/* + * Export flags. + */ +#define NFSEXP_READONLY 0x0001 +#define NFSEXP_INSECURE_PORT 0x0002 +#define NFSEXP_ROOTSQUASH 0x0004 +#define NFSEXP_ALLSQUASH 0x0008 +#define NFSEXP_ASYNC 0x0010 +#define NFSEXP_GATHERED_WRITES 0x0020 +/* 40 80 100 currently unused */ +#define NFSEXP_NOHIDE 0x0200 +#define NFSEXP_NOSUBTREECHECK 0x0400 +#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ +#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */ +#define NFSEXP_FSID 0x2000 +#define NFSEXP_CROSSMOUNT 0x4000 +#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ +/* + * The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4 + * clients, and only to the single directory that is the root of the + * export; further lookup and readdir operations are treated as if every + * subdirectory was a mountpoint, and ignored if they are not themselves + * exported. This is used by nfsd and mountd to construct the NFSv4 + * pseudofilesystem, which provides access only to paths leading to each + * exported filesystem. + */ +#define NFSEXP_V4ROOT 0x10000 +/* All flags that we claim to support. (Note we don't support NOACL.) */ +#define NFSEXP_ALLFLAGS 0x17E3F + +/* The flags that may vary depending on security flavor: */ +#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ + | NFSEXP_ALLSQUASH \ + | NFSEXP_INSECURE_PORT) + + +#endif /* _UAPINFSD_EXPORT_H */ diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h new file mode 100644 index 000000000000..616e3b396476 --- /dev/null +++ b/include/uapi/linux/nfsd/nfsfh.h @@ -0,0 +1,122 @@ +/* + * include/linux/nfsd/nfsfh.h + * + * This file describes the layout of the file handles as passed + * over the wire. + * + * Earlier versions of knfsd used to sign file handles using keyed MD5 + * or SHA. I've removed this code, because it doesn't give you more + * security than blocking external access to port 2049 on your firewall. + * + * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _UAPI_LINUX_NFSD_FH_H +#define _UAPI_LINUX_NFSD_FH_H + +#include <linux/types.h> +#include <linux/nfs.h> +#include <linux/nfs2.h> +#include <linux/nfs3.h> +#include <linux/nfs4.h> + +/* + * This is the old "dentry style" Linux NFSv2 file handle. + * + * The xino and xdev fields are currently used to transport the + * ino/dev of the exported inode. + */ +struct nfs_fhbase_old { + __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ + __u32 fb_ino; /* our inode number */ + __u32 fb_dirino; /* dir inode number, 0 for directories */ + __u32 fb_dev; /* our device */ + __u32 fb_xdev; + __u32 fb_xino; + __u32 fb_generation; +}; + +/* + * This is the new flexible, extensible style NFSv2/v3 file handle. + * by Neil Brown <neilb@cse.unsw.edu.au> - March 2000 + * + * The file handle starts with a sequence of four-byte words. + * The first word contains a version number (1) and three descriptor bytes + * that tell how the remaining 3 variable length fields should be handled. + * These three bytes are auth_type, fsid_type and fileid_type. + * + * All four-byte values are in host-byte-order. + * + * The auth_type field specifies how the filehandle can be authenticated + * This might allow a file to be confirmed to be in a writable part of a + * filetree without checking the path from it up to the root. + * Current values: + * 0 - No authentication. fb_auth is 0 bytes long + * Possible future values: + * 1 - 4 bytes taken from MD5 hash of the remainer of the file handle + * prefixed by a secret and with the important export flags. + * + * The fsid_type identifies how the filesystem (or export point) is + * encoded. + * Current values: + * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number + * NOTE: we cannot use the kdev_t device id value, because kdev_t.h + * says we mustn't. We must break it up and reassemble. + * 1 - 4 byte user specified identifier + * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED + * 3 - 4 byte device id, encoded for user-space, 4 byte inode number + * 4 - 4 byte inode number and 4 byte uuid + * 5 - 8 byte uuid + * 6 - 16 byte uuid + * 7 - 8 byte inode number and 16 byte uuid + * + * The fileid_type identified how the file within the filesystem is encoded. + * This is (will be) passed to, and set by, the underlying filesystem if it supports + * filehandle operations. The filesystem must not use the value '0' or '0xff' and may + * only use the values 1 and 2 as defined below: + * Current values: + * 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes. + * 1 - 32bit inode number, 32 bit generation number. + * 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number. + * + */ +struct nfs_fhbase_new { + __u8 fb_version; /* == 1, even => nfs_fhbase_old */ + __u8 fb_auth_type; + __u8 fb_fsid_type; + __u8 fb_fileid_type; + __u32 fb_auth[1]; +/* __u32 fb_fsid[0]; floating */ +/* __u32 fb_fileid[0]; floating */ +}; + +struct knfsd_fh { + unsigned int fh_size; /* significant for NFSv3. + * Points to the current size while building + * a new file handle + */ + union { + struct nfs_fhbase_old fh_old; + __u32 fh_pad[NFS4_FHSIZE/4]; + struct nfs_fhbase_new fh_new; + } fh_base; +}; + +#define ofh_dcookie fh_base.fh_old.fb_dcookie +#define ofh_ino fh_base.fh_old.fb_ino +#define ofh_dirino fh_base.fh_old.fb_dirino +#define ofh_dev fh_base.fh_old.fb_dev +#define ofh_xdev fh_base.fh_old.fb_xdev +#define ofh_xino fh_base.fh_old.fb_xino +#define ofh_generation fh_base.fh_old.fb_generation + +#define fh_version fh_base.fh_new.fb_version +#define fh_fsid_type fh_base.fh_new.fb_fsid_type +#define fh_auth_type fh_base.fh_new.fb_auth_type +#define fh_fileid_type fh_base.fh_new.fb_fileid_type +#define fh_auth fh_base.fh_new.fb_auth +#define fh_fsid fh_base.fh_new.fb_auth + + + +#endif /* _UAPI_LINUX_NFSD_FH_H */ diff --git a/include/uapi/linux/nfsd/stats.h b/include/uapi/linux/nfsd/stats.h new file mode 100644 index 000000000000..9fb7a0644263 --- /dev/null +++ b/include/uapi/linux/nfsd/stats.h @@ -0,0 +1,17 @@ +/* + * linux/include/linux/nfsd/stats.h + * + * Statistics for NFS server. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _UAPILINUX_NFSD_STATS_H +#define _UAPILINUX_NFSD_STATS_H + +#include <linux/nfs4.h> + +/* thread usage wraps very million seconds (approx one fortnight) */ +#define NFSD_USAGE_WRAP (HZ*1000000) + +#endif /* _UAPILINUX_NFSD_STATS_H */ diff --git a/include/uapi/linux/sunrpc/Kbuild b/include/uapi/linux/sunrpc/Kbuild index aafaa5aa54d4..8e02e47c20fb 100644 --- a/include/uapi/linux/sunrpc/Kbuild +++ b/include/uapi/linux/sunrpc/Kbuild @@ -1 +1,2 @@ # UAPI Header export list +header-y += debug.h diff --git a/include/uapi/linux/sunrpc/debug.h b/include/uapi/linux/sunrpc/debug.h new file mode 100644 index 000000000000..830e34493a8c --- /dev/null +++ b/include/uapi/linux/sunrpc/debug.h @@ -0,0 +1,48 @@ +/* + * linux/include/linux/sunrpc/debug.h + * + * Debugging support for sunrpc module + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _UAPI_LINUX_SUNRPC_DEBUG_H_ +#define _UAPI_LINUX_SUNRPC_DEBUG_H_ + +/* + * RPC debug facilities + */ +#define RPCDBG_XPRT 0x0001 +#define RPCDBG_CALL 0x0002 +#define RPCDBG_DEBUG 0x0004 +#define RPCDBG_NFS 0x0008 +#define RPCDBG_AUTH 0x0010 +#define RPCDBG_BIND 0x0020 +#define RPCDBG_SCHED 0x0040 +#define RPCDBG_TRANS 0x0080 +#define RPCDBG_SVCXPRT 0x0100 +#define RPCDBG_SVCDSP 0x0200 +#define RPCDBG_MISC 0x0400 +#define RPCDBG_CACHE 0x0800 +#define RPCDBG_ALL 0x7fff + + +/* + * Declarations for the sysctl debug interface, which allows to read or + * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc + * module currently registers its sysctl table dynamically, the sysctl path + * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>. + */ + +enum { + CTL_RPCDEBUG = 1, + CTL_NFSDEBUG, + CTL_NFSDDEBUG, + CTL_NLMDEBUG, + CTL_SLOTTABLE_UDP, + CTL_SLOTTABLE_TCP, + CTL_MIN_RESVPORT, + CTL_MAX_RESVPORT, +}; + +#endif /* _UAPI_LINUX_SUNRPC_DEBUG_H_ */ diff --git a/include/uapi/linux/wimax/Kbuild b/include/uapi/linux/wimax/Kbuild index aafaa5aa54d4..1c97be49971f 100644 --- a/include/uapi/linux/wimax/Kbuild +++ b/include/uapi/linux/wimax/Kbuild @@ -1 +1,2 @@ # UAPI Header export list +header-y += i2400m.h diff --git a/include/linux/wimax/i2400m.h b/include/uapi/linux/wimax/i2400m.h index 62d356153565..62d356153565 100644 --- a/include/linux/wimax/i2400m.h +++ b/include/uapi/linux/wimax/i2400m.h diff --git a/include/video/omapdss.h b/include/video/omapdss.h index a6267a2d292b..3729173b7fbc 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -48,10 +48,10 @@ #define DISPC_IRQ_FRAMEDONEWB (1 << 23) #define DISPC_IRQ_FRAMEDONETV (1 << 24) #define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25) -#define DISPC_IRQ_FRAMEDONE3 (1 << 26) -#define DISPC_IRQ_VSYNC3 (1 << 27) -#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 28) -#define DISPC_IRQ_SYNC_LOST3 (1 << 29) +#define DISPC_IRQ_SYNC_LOST3 (1 << 27) +#define DISPC_IRQ_VSYNC3 (1 << 28) +#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) +#define DISPC_IRQ_FRAMEDONE3 (1 << 30) struct omap_dss_device; struct omap_overlay_manager; @@ -73,6 +73,7 @@ enum omap_plane { OMAP_DSS_VIDEO1 = 1, OMAP_DSS_VIDEO2 = 2, OMAP_DSS_VIDEO3 = 3, + OMAP_DSS_WB = 4, }; enum omap_channel { @@ -186,6 +187,8 @@ enum omap_overlay_caps { OMAP_DSS_OVL_CAP_GLOBAL_ALPHA = 1 << 1, OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA = 1 << 2, OMAP_DSS_OVL_CAP_ZORDER = 1 << 3, + OMAP_DSS_OVL_CAP_POS = 1 << 4, + OMAP_DSS_OVL_CAP_REPLICATION = 1 << 5, }; enum omap_overlay_manager_caps { @@ -207,6 +210,16 @@ enum omap_hdmi_flags { OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, }; +enum omap_dss_output_id { + OMAP_DSS_OUTPUT_DPI = 1 << 0, + OMAP_DSS_OUTPUT_DBI = 1 << 1, + OMAP_DSS_OUTPUT_SDI = 1 << 2, + OMAP_DSS_OUTPUT_DSI1 = 1 << 3, + OMAP_DSS_OUTPUT_DSI2 = 1 << 4, + OMAP_DSS_OUTPUT_VENC = 1 << 5, + OMAP_DSS_OUTPUT_HDMI = 1 << 6, +}; + /* RFBI */ struct rfbi_timings { @@ -243,7 +256,7 @@ void rfbi_bus_unlock(void); /* DSI */ -struct omap_dss_dsi_videomode_data { +struct omap_dss_dsi_videomode_timings { /* DSI video mode blanking data */ /* Unit: byte clock cycles */ u16 hsa; @@ -424,6 +437,8 @@ struct omap_overlay { struct omap_overlay_info *info); int (*wait_for_go)(struct omap_overlay *ovl); + + struct omap_dss_device *(*get_device)(struct omap_overlay *ovl); }; struct omap_overlay_manager_info { @@ -448,9 +463,10 @@ struct omap_overlay_manager { enum omap_overlay_manager_caps caps; struct list_head overlays; enum omap_display_type supported_displays; + enum omap_dss_output_id supported_outputs; /* dynamic fields */ - struct omap_dss_device *device; + struct omap_dss_output *output; /* * The following functions do not block: @@ -463,9 +479,9 @@ struct omap_overlay_manager { * interrupt context */ - int (*set_device)(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev); - int (*unset_device)(struct omap_overlay_manager *mgr); + int (*set_output)(struct omap_overlay_manager *mgr, + struct omap_dss_output *output); + int (*unset_output)(struct omap_overlay_manager *mgr); int (*set_manager_info)(struct omap_overlay_manager *mgr, struct omap_overlay_manager_info *info); @@ -475,6 +491,8 @@ struct omap_overlay_manager { int (*apply)(struct omap_overlay_manager *mgr); int (*wait_for_go)(struct omap_overlay_manager *mgr); int (*wait_for_vsync)(struct omap_overlay_manager *mgr); + + struct omap_dss_device *(*get_device)(struct omap_overlay_manager *mgr); }; /* 22 pins means 1 clk lane and 10 data lanes */ @@ -492,6 +510,37 @@ struct omap_dsi_pin_config { int pins[OMAP_DSS_MAX_DSI_PINS]; }; +struct omap_dss_writeback_info { + u32 paddr; + u32 p_uv_addr; + u16 buf_width; + u16 width; + u16 height; + enum omap_color_mode color_mode; + u8 rotation; + enum omap_dss_rotation_type rotation_type; + bool mirror; + u8 pre_mult_alpha; +}; + +struct omap_dss_output { + struct list_head list; + + /* display type supported by the output */ + enum omap_display_type type; + + /* output instance */ + enum omap_dss_output_id id; + + /* output's platform device pointer */ + struct platform_device *pdev; + + /* dynamic fields */ + struct omap_overlay_manager *manager; + + struct omap_dss_device *device; +}; + struct omap_dss_device { struct device dev; @@ -564,7 +613,7 @@ struct omap_dss_device { enum omap_dss_dsi_pixel_format dsi_pix_fmt; enum omap_dss_dsi_mode dsi_mode; - struct omap_dss_dsi_videomode_data dsi_vm_data; + struct omap_dss_dsi_videomode_timings dsi_vm_timings; } panel; struct { @@ -590,7 +639,7 @@ struct omap_dss_device { enum omap_display_caps caps; - struct omap_overlay_manager *manager; + struct omap_dss_output *output; enum omap_dss_display_state state; @@ -605,6 +654,8 @@ struct omap_dss_device { struct omap_dss_hdmi_data { + int ct_cp_hpd_gpio; + int ls_oe_gpio; int hpd_gpio; }; @@ -699,6 +750,11 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); int omap_dss_get_num_overlays(void); struct omap_overlay *omap_dss_get_overlay(int num); +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id); +int omapdss_output_set_device(struct omap_dss_output *out, + struct omap_dss_device *dssdev); +int omapdss_output_unset_device(struct omap_dss_output *out); + void omapdss_default_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres); int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev); @@ -719,6 +775,15 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable); int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h); +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt); +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode); +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings); int omap_dsi_update(struct omap_dss_device *dssdev, int channel, void (*callback)(int, void *), void *data); @@ -727,6 +792,8 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel); int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, const struct omap_dsi_pin_config *pin_cfg); +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk); int omapdss_dsi_display_enable(struct omap_dss_device *dssdev); void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, @@ -734,22 +801,29 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, int omapdss_dpi_display_enable(struct omap_dss_device *dssdev); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev); -void dpi_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings); +void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings); +void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines); int omapdss_sdi_display_enable(struct omap_dss_device *dssdev); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev); +void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs); int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev); void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev); -int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h); -int omap_rfbi_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(void *), void *data); -int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, +int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), + void *data); +int omap_rfbi_configure(struct omap_dss_device *dssdev); +void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h); +void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, + int pixel_size); +void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines); +void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, + struct rfbi_timings *timings); #endif diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/include/video/samsung_fimd.h index 9a78012d6f43..7ae6c07f2ef8 100644 --- a/arch/arm/plat-samsung/include/plat/regs-fb.h +++ b/include/video/samsung_fimd.h @@ -1,13 +1,13 @@ -/* arch/arm/plat-samsung/include/plat/regs-fb.h +/* include/video/samsung_fimd.h * * Copyright 2008 Openmoko, Inc. * Copyright 2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> * - * S3C Platform - new-style framebuffer register definitions + * S3C Platform - new-style fimd and framebuffer register definitions * - * This is the register set for the new style framebuffer interface + * This is the register set for the fimd and new style framebuffer interface * found from the S3C2443 onwards into the S3C2416, S3C2450 and the * S3C64XX series such as the S3C6400 and S3C6410. * @@ -15,19 +15,11 @@ * whichever architecture is selected, it only contains the core of the * register set. See <mach/regs-fb.h> to get the specifics. * - * Note, we changed to using regs-fb.h as it avoids any clashes with - * the original regs-lcd.h so out of the way of regs-lcd.h as well as - * indicating the newer block is much more than just an LCD interface. - * * 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. */ -/* Please do not include this file directly, use <mach/regs-fb.h> to - * ensure all the localised SoC support is included as necessary. -*/ - /* VIDCON0 */ #define VIDCON0 (0x00) @@ -401,3 +393,141 @@ #define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0) #define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0) +#define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */ +#define VIDCON1_FSTATUS_EVEN (1 << 15) + +/* Video timing controls */ +#define VIDTCON0 (0x10) +#define VIDTCON1 (0x14) +#define VIDTCON2 (0x18) + +/* Window position controls */ + +#define WINCON(_win) (0x20 + ((_win) * 4)) + +/* OSD1 and OSD4 do not have register D */ + +#define VIDOSD_BASE (0x40) + +#define VIDINTCON0 (0x130) + +/* WINCONx */ + +#define WINCONx_CSCWIDTH_MASK (0x3 << 26) +#define WINCONx_CSCWIDTH_SHIFT (26) +#define WINCONx_CSCWIDTH_WIDE (0x0 << 26) +#define WINCONx_CSCWIDTH_NARROW (0x3 << 26) + +#define WINCONx_ENLOCAL (1 << 22) +#define WINCONx_BUFSTATUS (1 << 21) +#define WINCONx_BUFSEL (1 << 20) +#define WINCONx_BUFAUTOEN (1 << 19) +#define WINCONx_YCbCr (1 << 13) + +#define WINCON1_LOCALSEL_CAMIF (1 << 23) + +#define WINCON2_LOCALSEL_CAMIF (1 << 23) +#define WINCON2_BLD_PIX (1 << 6) + +#define WINCON2_ALPHA_SEL (1 << 1) +#define WINCON2_BPPMODE_MASK (0xf << 2) +#define WINCON2_BPPMODE_SHIFT (2) +#define WINCON2_BPPMODE_1BPP (0x0 << 2) +#define WINCON2_BPPMODE_2BPP (0x1 << 2) +#define WINCON2_BPPMODE_4BPP (0x2 << 2) +#define WINCON2_BPPMODE_8BPP_1232 (0x4 << 2) +#define WINCON2_BPPMODE_16BPP_565 (0x5 << 2) +#define WINCON2_BPPMODE_16BPP_A1555 (0x6 << 2) +#define WINCON2_BPPMODE_16BPP_I1555 (0x7 << 2) +#define WINCON2_BPPMODE_18BPP_666 (0x8 << 2) +#define WINCON2_BPPMODE_18BPP_A1665 (0x9 << 2) +#define WINCON2_BPPMODE_19BPP_A1666 (0xa << 2) +#define WINCON2_BPPMODE_24BPP_888 (0xb << 2) +#define WINCON2_BPPMODE_24BPP_A1887 (0xc << 2) +#define WINCON2_BPPMODE_25BPP_A1888 (0xd << 2) +#define WINCON2_BPPMODE_28BPP_A4888 (0xd << 2) + +#define WINCON3_BLD_PIX (1 << 6) + +#define WINCON3_ALPHA_SEL (1 << 1) +#define WINCON3_BPPMODE_MASK (0xf << 2) +#define WINCON3_BPPMODE_SHIFT (2) +#define WINCON3_BPPMODE_1BPP (0x0 << 2) +#define WINCON3_BPPMODE_2BPP (0x1 << 2) +#define WINCON3_BPPMODE_4BPP (0x2 << 2) +#define WINCON3_BPPMODE_16BPP_565 (0x5 << 2) +#define WINCON3_BPPMODE_16BPP_A1555 (0x6 << 2) +#define WINCON3_BPPMODE_16BPP_I1555 (0x7 << 2) +#define WINCON3_BPPMODE_18BPP_666 (0x8 << 2) +#define WINCON3_BPPMODE_18BPP_A1665 (0x9 << 2) +#define WINCON3_BPPMODE_19BPP_A1666 (0xa << 2) +#define WINCON3_BPPMODE_24BPP_888 (0xb << 2) +#define WINCON3_BPPMODE_24BPP_A1887 (0xc << 2) +#define WINCON3_BPPMODE_25BPP_A1888 (0xd << 2) +#define WINCON3_BPPMODE_28BPP_A4888 (0xd << 2) + +#define VIDINTCON0_FIFIOSEL_WINDOW2 (0x10 << 5) +#define VIDINTCON0_FIFIOSEL_WINDOW3 (0x20 << 5) +#define VIDINTCON0_FIFIOSEL_WINDOW4 (0x40 << 5) + +#define DITHMODE (0x170) +#define WINxMAP(_win) (0x180 + ((_win) * 4)) + + +#define DITHMODE_R_POS_MASK (0x3 << 5) +#define DITHMODE_R_POS_SHIFT (5) +#define DITHMODE_R_POS_8BIT (0x0 << 5) +#define DITHMODE_R_POS_6BIT (0x1 << 5) +#define DITHMODE_R_POS_5BIT (0x2 << 5) + +#define DITHMODE_G_POS_MASK (0x3 << 3) +#define DITHMODE_G_POS_SHIFT (3) +#define DITHMODE_G_POS_8BIT (0x0 << 3) +#define DITHMODE_G_POS_6BIT (0x1 << 3) +#define DITHMODE_G_POS_5BIT (0x2 << 3) + +#define DITHMODE_B_POS_MASK (0x3 << 1) +#define DITHMODE_B_POS_SHIFT (1) +#define DITHMODE_B_POS_8BIT (0x0 << 1) +#define DITHMODE_B_POS_6BIT (0x1 << 1) +#define DITHMODE_B_POS_5BIT (0x2 << 1) + +#define DITHMODE_DITH_EN (1 << 0) + +#define WPALCON (0x1A0) + +/* Palette control */ +/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L), + * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */ +#define WPALCON_W4PAL_16BPP_A555 (1 << 8) +#define WPALCON_W3PAL_16BPP_A555 (1 << 7) +#define WPALCON_W2PAL_16BPP_A555 (1 << 6) + + +/* Notes on per-window bpp settings + * + * Value Win0 Win1 Win2 Win3 Win 4 + * 0000 1(P) 1(P) 1(P) 1(P) 1(P) + * 0001 2(P) 2(P) 2(P) 2(P) 2(P) + * 0010 4(P) 4(P) 4(P) 4(P) -none- + * 0011 8(P) 8(P) -none- -none- -none- + * 0100 -none- 8(A232) 8(A232) -none- -none- + * 0101 16(565) 16(565) 16(565) 16(565) 16(565) + * 0110 -none- 16(A555) 16(A555) 16(A555) 16(A555) + * 0111 16(I555) 16(I565) 16(I555) 16(I555) 16(I555) + * 1000 18(666) 18(666) 18(666) 18(666) 18(666) + * 1001 -none- 18(A665) 18(A665) 18(A665) 16(A665) + * 1010 -none- 19(A666) 19(A666) 19(A666) 19(A666) + * 1011 24(888) 24(888) 24(888) 24(888) 24(888) + * 1100 -none- 24(A887) 24(A887) 24(A887) 24(A887) + * 1101 -none- 25(A888) 25(A888) 25(A888) 25(A888) + * 1110 -none- -none- -none- -none- -none- + * 1111 -none- -none- -none- -none- -none- +*/ + +/* FIMD Version 8 register offset definitions */ +#define FIMD_V8_VIDTCON0 (0x20010) +#define FIMD_V8_VIDTCON1 (0x20014) +#define FIMD_V8_VIDTCON2 (0x20018) +#define FIMD_V8_VIDTCON3 (0x2001C) +#define FIMD_V8_VIDCON1 (0x20004) diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h index a4827f46ee97..956a04682865 100644 --- a/include/xen/interface/hvm/hvm_op.h +++ b/include/xen/interface/hvm/hvm_op.h @@ -43,4 +43,23 @@ struct xen_hvm_pagetable_dying { typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t; DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_pagetable_dying_t); +enum hvmmem_type_t { + HVMMEM_ram_rw, /* Normal read/write guest RAM */ + HVMMEM_ram_ro, /* Read-only; writes are discarded */ + HVMMEM_mmio_dm, /* Reads and write go to the device model */ +}; + +#define HVMOP_get_mem_type 15 +/* Return hvmmem_type_t for the specified pfn. */ +struct xen_hvm_get_mem_type { + /* Domain to be queried. */ + domid_t domid; + /* OUT variable. */ + uint16_t mem_type; + uint16_t pad[2]; /* align next field on 8-byte boundary */ + /* IN variable. */ + uint64_t pfn; +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_mem_type); + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ diff --git a/init/Kconfig b/init/Kconfig index 4c93533da42c..89e4cf672dfe 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -496,6 +496,12 @@ config RCU_USER_QS excluded from the global RCU state machine and thus doesn't to keep the timer tick on for RCU. + Unless you want to hack and help the development of the full + tickless feature, you shouldn't enable this option. It adds + unnecessary overhead. + + If unsure say N + config RCU_USER_QS_FORCE bool "Force userspace extended QS by default" depends on RCU_USER_QS @@ -504,6 +510,12 @@ config RCU_USER_QS_FORCE test this feature that treats userspace as an extended quiescent state until we have a real user like a full adaptive nohz option. + Unless you want to hack and help the development of the full + tickless feature, you shouldn't enable this option. It adds + unnecessary overhead. + + If unsure say N + config RCU_FANOUT int "Tree-based hierarchical RCU fanout value" range 2 64 if 64BIT diff --git a/init/do_mounts.c b/init/do_mounts.c index d3f0aeed2d39..f8a66424360d 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -353,8 +353,9 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) void __init mount_block_root(char *name, int flags) { - char *fs_names = __getname_gfp(GFP_KERNEL - | __GFP_NOTRACK_FALSE_POSITIVE); + struct page *page = alloc_page(GFP_KERNEL | + __GFP_NOTRACK_FALSE_POSITIVE); + char *fs_names = page_address(page); char *p; #ifdef CONFIG_BLOCK char b[BDEVNAME_SIZE]; @@ -406,7 +407,7 @@ retry: #endif panic("VFS: Unable to mount root fs on %s", b); out: - putname(fs_names); + put_page(page); } #ifdef CONFIG_ROOT_NFS diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 135959a276be..5e4ded51788e 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -16,13 +16,13 @@ #include <linux/initrd.h> #include <linux/sched.h> #include <linux/freezer.h> +#include <linux/kmod.h> #include "do_mounts.h" unsigned long initrd_start, initrd_end; int initrd_below_start_ok; unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ -static int __initdata old_fd, root_fd; static int __initdata mount_initrd = 1; static int __init no_initrd(char *str) @@ -33,33 +33,29 @@ static int __init no_initrd(char *str) __setup("noinitrd", no_initrd); -static int __init do_linuxrc(void *_shell) +static int init_linuxrc(struct subprocess_info *info, struct cred *new) { - static const char *argv[] = { "linuxrc", NULL, }; - extern const char *envp_init[]; - const char *shell = _shell; - - sys_close(old_fd);sys_close(root_fd); + sys_unshare(CLONE_FS | CLONE_FILES); + /* move initrd over / and chdir/chroot in initrd root */ + sys_chdir("/root"); + sys_mount(".", "/", NULL, MS_MOVE, NULL); + sys_chroot("."); sys_setsid(); - return kernel_execve(shell, argv, envp_init); + return 0; } static void __init handle_initrd(void) { + static char *argv[] = { "linuxrc", NULL, }; + extern char *envp_init[]; int error; - int pid; real_root_dev = new_encode_dev(ROOT_DEV); create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); sys_mkdir("/old", 0700); - root_fd = sys_open("/", 0, 0); - old_fd = sys_open("/old", 0, 0); - /* move initrd over / and chdir/chroot in initrd root */ - sys_chdir("/root"); - sys_mount(".", "/", NULL, MS_MOVE, NULL); - sys_chroot("."); + sys_chdir("/old"); /* * In case that a resume from disk is carried out by linuxrc or one of @@ -67,27 +63,22 @@ static void __init handle_initrd(void) */ current->flags |= PF_FREEZER_SKIP; - pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); - if (pid > 0) - while (pid != sys_wait4(-1, NULL, 0, NULL)) - yield(); + call_usermodehelper_fns("/linuxrc", argv, envp_init, UMH_WAIT_PROC, + init_linuxrc, NULL, NULL); current->flags &= ~PF_FREEZER_SKIP; /* move initrd to rootfs' /old */ - sys_fchdir(old_fd); - sys_mount("/", ".", NULL, MS_MOVE, NULL); + sys_mount("..", ".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ - sys_fchdir(root_fd); - sys_chroot("."); - sys_close(old_fd); - sys_close(root_fd); + sys_chroot(".."); if (new_decode_dev(real_root_dev) == Root_RAM0) { sys_chdir("/old"); return; } + sys_chdir("/"); ROOT_DEV = new_decode_dev(real_root_dev); mount_root(); diff --git a/init/main.c b/init/main.c index 313360fe1118..9cf77ab138a6 100644 --- a/init/main.c +++ b/init/main.c @@ -69,6 +69,7 @@ #include <linux/slab.h> #include <linux/perf_event.h> #include <linux/file.h> +#include <linux/ptrace.h> #include <asm/io.h> #include <asm/bugs.h> @@ -791,17 +792,17 @@ static void __init do_pre_smp_initcalls(void) do_one_initcall(*fn); } -static void run_init_process(const char *init_filename) +static int run_init_process(const char *init_filename) { argv_init[0] = init_filename; - kernel_execve(init_filename, argv_init, envp_init); + return kernel_execve(init_filename, argv_init, envp_init); } -/* This is a non __init function. Force it to be noinline otherwise gcc - * makes it inline to init() and it becomes part of init.text section - */ -static noinline int init_post(void) +static void __init kernel_init_freeable(void); + +static int __ref kernel_init(void *unused) { + kernel_init_freeable(); /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); free_initmem(); @@ -813,7 +814,8 @@ static noinline int init_post(void) flush_delayed_fput(); if (ramdisk_execute_command) { - run_init_process(ramdisk_execute_command); + if (!run_init_process(ramdisk_execute_command)) + return 0; printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command); } @@ -825,20 +827,22 @@ static noinline int init_post(void) * trying to recover a really broken machine. */ if (execute_command) { - run_init_process(execute_command); + if (!run_init_process(execute_command)) + return 0; printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } - run_init_process("/sbin/init"); - run_init_process("/etc/init"); - run_init_process("/bin/init"); - run_init_process("/bin/sh"); + if (!run_init_process("/sbin/init") || + !run_init_process("/etc/init") || + !run_init_process("/bin/init") || + !run_init_process("/bin/sh")) + return 0; panic("No init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); } -static int __init kernel_init(void * unused) +static void __init kernel_init_freeable(void) { /* * Wait until kthreadd is all set-up. @@ -893,7 +897,4 @@ static int __init kernel_init(void * unused) * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. */ - - init_post(); - return 0; } diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 6b97e2466fad..71a3ca18c873 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -772,7 +772,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, { struct path path; struct file *filp; - char *name; + struct filename *name; struct mq_attr attr; int fd, error; struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; @@ -795,7 +795,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ro = mnt_want_write(mnt); /* we'll drop it in any case */ error = 0; mutex_lock(&root->d_inode->i_mutex); - path.dentry = lookup_one_len(name, root, strlen(name)); + path.dentry = lookup_one_len(name->name, root, strlen(name->name)); if (IS_ERR(path.dentry)) { error = PTR_ERR(path.dentry); goto out_putfd; @@ -804,7 +804,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, if (oflag & O_CREAT) { if (path.dentry->d_inode) { /* entry already exists */ - audit_inode(name, path.dentry); + audit_inode(name, path.dentry, 0); if (oflag & O_EXCL) { error = -EEXIST; goto out; @@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, error = -ENOENT; goto out; } - audit_inode(name, path.dentry); + audit_inode(name, path.dentry, 0); filp = do_open(&path, oflag); } @@ -849,7 +849,7 @@ out_putname: SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) { int err; - char *name; + struct filename *name; struct dentry *dentry; struct inode *inode = NULL; struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; @@ -863,7 +863,8 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) if (err) goto out_name; mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT); - dentry = lookup_one_len(name, mnt->mnt_root, strlen(name)); + dentry = lookup_one_len(name->name, mnt->mnt_root, + strlen(name->name)); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out_unlock; @@ -978,7 +979,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, goto out_fput; } info = MQUEUE_I(inode); - audit_inode(NULL, f.file->f_path.dentry); + audit_inode(NULL, f.file->f_path.dentry, 0); if (unlikely(!(f.file->f_mode & FMODE_WRITE))) { ret = -EBADF; @@ -1094,7 +1095,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, goto out_fput; } info = MQUEUE_I(inode); - audit_inode(NULL, f.file->f_path.dentry); + audit_inode(NULL, f.file->f_path.dentry, 0); if (unlikely(!(f.file->f_mode & FMODE_READ))) { ret = -EBADF; diff --git a/kernel/acct.c b/kernel/acct.c index 6cd7529c9e6a..051e071a06e7 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file, } } -static int acct_on(char *name) +static int acct_on(struct filename *pathname) { struct file *file; struct vfsmount *mnt; @@ -201,7 +201,7 @@ static int acct_on(char *name) struct bsd_acct_struct *acct = NULL; /* Difference from BSD - they don't do O_APPEND */ - file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); + file = file_open_name(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0); if (IS_ERR(file)) return PTR_ERR(file); @@ -260,7 +260,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name) return -EPERM; if (name) { - char *tmp = getname(name); + struct filename *tmp = getname(name); if (IS_ERR(tmp)) return (PTR_ERR(tmp)); error = acct_on(tmp); diff --git a/kernel/audit.c b/kernel/audit.c index 4d0ceede3319..40414e9143db 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1440,6 +1440,8 @@ void audit_log_link_denied(const char *operation, struct path *link) ab = audit_log_start(current->audit_context, GFP_KERNEL, AUDIT_ANOM_LINK); + if (!ab) + return; audit_log_format(ab, "op=%s action=denied", operation); audit_log_format(ab, " pid=%d comm=", current->pid); audit_log_untrustedstring(ab, current->comm); diff --git a/kernel/audit.h b/kernel/audit.h index 9eb3d79482b6..d51cba868e1b 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -74,12 +74,15 @@ static inline int audit_hash_ino(u32 ino) return (ino & (AUDIT_INODE_BUCKETS-1)); } +/* Indicates that audit should log the full pathname. */ +#define AUDIT_NAME_FULL -1 + extern int audit_match_class(int class, unsigned syscall); extern int audit_comparator(const u32 left, const u32 op, const u32 right); extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); -extern int audit_compare_dname_path(const char *dname, const char *path, - int *dirlen); +extern int parent_len(const char *path); +extern int audit_compare_dname_path(const char *dname, const char *path, int plen); extern struct sk_buff * audit_make_reply(int pid, int seq, int type, int done, int multi, const void *payload, int size); diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 1c22ec3d87bc..9a9ae6e3d290 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -265,7 +265,8 @@ static void audit_update_watch(struct audit_parent *parent, /* Run all of the watches on this parent looking for the one that * matches the given dname */ list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { - if (audit_compare_dname_path(dname, owatch->path, NULL)) + if (audit_compare_dname_path(dname, owatch->path, + AUDIT_NAME_FULL)) continue; /* If the update involves invalidating rules, do the inode-based diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index c4bcdbaf4d4d..7f19f23d38a3 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1298,41 +1298,60 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right) } } -/* Compare given dentry name with last component in given path, - * return of 0 indicates a match. */ -int audit_compare_dname_path(const char *dname, const char *path, - int *dirlen) +/** + * parent_len - find the length of the parent portion of a pathname + * @path: pathname of which to determine length + */ +int parent_len(const char *path) { - int dlen, plen; + int plen; const char *p; - if (!dname || !path) - return 1; - - dlen = strlen(dname); plen = strlen(path); - if (plen < dlen) - return 1; + + if (plen == 0) + return plen; /* disregard trailing slashes */ p = path + plen - 1; while ((*p == '/') && (p > path)) p--; - /* find last path component */ - p = p - dlen + 1; - if (p < path) + /* walk backward until we find the next slash or hit beginning */ + while ((*p != '/') && (p > path)) + p--; + + /* did we find a slash? Then increment to include it in path */ + if (*p == '/') + p++; + + return p - path; +} + +/** + * audit_compare_dname_path - compare given dentry name with last component in + * given path. Return of 0 indicates a match. + * @dname: dentry name that we're comparing + * @path: full pathname that we're comparing + * @parentlen: length of the parent if known. Passing in AUDIT_NAME_FULL + * here indicates that we must compute this value. + */ +int audit_compare_dname_path(const char *dname, const char *path, int parentlen) +{ + int dlen, pathlen; + const char *p; + + dlen = strlen(dname); + pathlen = strlen(path); + if (pathlen < dlen) return 1; - else if (p > path) { - if (*--p != '/') - return 1; - else - p++; - } - /* return length of path's directory component */ - if (dirlen) - *dirlen = p - path; + parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen; + if (pathlen - parentlen != dlen) + return 1; + + p = path + parentlen; + return strncmp(p, dname, dlen); } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index f4a7756f999c..2f186ed80c40 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -81,9 +81,6 @@ * a name dynamically and also add those to the list anchored by names_list. */ #define AUDIT_NAMES 5 -/* Indicates that audit should log the full pathname. */ -#define AUDIT_NAME_FULL -1 - /* no execve audit message should be longer than this (userspace limits) */ #define MAX_EXECVE_AUDIT_LEN 7500 @@ -106,27 +103,29 @@ struct audit_cap_data { * we don't let putname() free it (instead we free all of the saved * pointers at syscall exit time). * - * Further, in fs/namei.c:path_lookup() we store the inode and device. */ + * Further, in fs/namei.c:path_lookup() we store the inode and device. + */ struct audit_names { - struct list_head list; /* audit_context->names_list */ - const char *name; - unsigned long ino; - dev_t dev; - umode_t mode; - kuid_t uid; - kgid_t gid; - dev_t rdev; - u32 osid; - struct audit_cap_data fcap; - unsigned int fcap_ver; - int name_len; /* number of name's characters to log */ - bool name_put; /* call __putname() for this name */ + struct list_head list; /* audit_context->names_list */ + struct filename *name; + unsigned long ino; + dev_t dev; + umode_t mode; + kuid_t uid; + kgid_t gid; + dev_t rdev; + u32 osid; + struct audit_cap_data fcap; + unsigned int fcap_ver; + int name_len; /* number of name's characters to log */ + unsigned char type; /* record type */ + bool name_put; /* call __putname() for this name */ /* * This was an allocated audit_names and not from the array of * names allocated in the task audit context. Thus this name * should be freed on syscall exit */ - bool should_free; + bool should_free; }; struct audit_aux_data { @@ -998,7 +997,7 @@ static inline void audit_free_names(struct audit_context *context) context->ino_count); list_for_each_entry(n, &context->names_list, list) { printk(KERN_ERR "names[%d] = %p = %s\n", i, - n->name, n->name ?: "(null)"); + n->name, n->name->name ?: "(null)"); } dump_stack(); return; @@ -1555,7 +1554,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, case AUDIT_NAME_FULL: /* log the full path */ audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, n->name); + audit_log_untrustedstring(ab, n->name->name); break; case 0: /* name was specified as a relative path and the @@ -1565,7 +1564,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, default: /* log the name's directory component */ audit_log_format(ab, " name="); - audit_log_n_untrustedstring(ab, n->name, + audit_log_n_untrustedstring(ab, n->name->name, n->name_len); } } else @@ -1995,7 +1994,8 @@ retry: #endif } -static struct audit_names *audit_alloc_name(struct audit_context *context) +static struct audit_names *audit_alloc_name(struct audit_context *context, + unsigned char type) { struct audit_names *aname; @@ -2010,6 +2010,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context) } aname->ino = (unsigned long)-1; + aname->type = type; list_add_tail(&aname->list, &context->names_list); context->name_count++; @@ -2020,13 +2021,36 @@ static struct audit_names *audit_alloc_name(struct audit_context *context) } /** + * audit_reusename - fill out filename with info from existing entry + * @uptr: userland ptr to pathname + * + * Search the audit_names list for the current audit context. If there is an + * existing entry with a matching "uptr" then return the filename + * associated with that audit_name. If not, return NULL. + */ +struct filename * +__audit_reusename(const __user char *uptr) +{ + struct audit_context *context = current->audit_context; + struct audit_names *n; + + list_for_each_entry(n, &context->names_list, list) { + if (!n->name) + continue; + if (n->name->uptr == uptr) + return n->name; + } + return NULL; +} + +/** * audit_getname - add a name to the list * @name: name to add * * Add a name to the list of audit names for this context. * Called from fs/namei.c:getname(). */ -void __audit_getname(const char *name) +void __audit_getname(struct filename *name) { struct audit_context *context = current->audit_context; struct audit_names *n; @@ -2040,13 +2064,19 @@ void __audit_getname(const char *name) return; } - n = audit_alloc_name(context); +#if AUDIT_DEBUG + /* The filename _must_ have a populated ->name */ + BUG_ON(!name->name); +#endif + + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); if (!n) return; n->name = name; n->name_len = AUDIT_NAME_FULL; n->name_put = true; + name->aname = n; if (!context->pwd.dentry) get_fs_pwd(current->fs, &context->pwd); @@ -2059,7 +2089,7 @@ void __audit_getname(const char *name) * then we delay the putname until syscall exit. * Called from include/linux/fs.h:putname(). */ -void audit_putname(const char *name) +void audit_putname(struct filename *name) { struct audit_context *context = current->audit_context; @@ -2074,7 +2104,7 @@ void audit_putname(const char *name) list_for_each_entry(n, &context->names_list, list) printk(KERN_ERR "name[%d] = %p = %s\n", i, - n->name, n->name ?: "(null)"); + n->name, n->name->name ?: "(null)"); } #endif __putname(name); @@ -2088,8 +2118,8 @@ void audit_putname(const char *name) " put_count=%d\n", __FILE__, __LINE__, context->serial, context->major, - context->in_syscall, name, context->name_count, - context->put_count); + context->in_syscall, name->name, + context->name_count, context->put_count); dump_stack(); } } @@ -2132,13 +2162,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent } /** - * audit_inode - store the inode and device from a lookup + * __audit_inode - store the inode and device from a lookup * @name: name being audited * @dentry: dentry being audited - * - * Called from fs/namei.c:path_lookup(). + * @parent: does this dentry represent the parent? */ -void __audit_inode(const char *name, const struct dentry *dentry) +void __audit_inode(struct filename *name, const struct dentry *dentry, + unsigned int parent) { struct audit_context *context = current->audit_context; const struct inode *inode = dentry->d_inode; @@ -2147,24 +2177,69 @@ void __audit_inode(const char *name, const struct dentry *dentry) if (!context->in_syscall) return; + if (!name) + goto out_alloc; + +#if AUDIT_DEBUG + /* The struct filename _must_ have a populated ->name */ + BUG_ON(!name->name); +#endif + /* + * If we have a pointer to an audit_names entry already, then we can + * just use it directly if the type is correct. + */ + n = name->aname; + if (n) { + if (parent) { + if (n->type == AUDIT_TYPE_PARENT || + n->type == AUDIT_TYPE_UNKNOWN) + goto out; + } else { + if (n->type != AUDIT_TYPE_PARENT) + goto out; + } + } + list_for_each_entry_reverse(n, &context->names_list, list) { - if (n->name && (n->name == name)) - goto out; + /* does the name pointer match? */ + if (!n->name || n->name->name != name->name) + continue; + + /* match the correct record type */ + if (parent) { + if (n->type == AUDIT_TYPE_PARENT || + n->type == AUDIT_TYPE_UNKNOWN) + goto out; + } else { + if (n->type != AUDIT_TYPE_PARENT) + goto out; + } } - /* unable to find the name from a previous getname() */ - n = audit_alloc_name(context); +out_alloc: + /* unable to find the name from a previous getname(). Allocate a new + * anonymous entry. + */ + n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); if (!n) return; out: + if (parent) { + n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; + n->type = AUDIT_TYPE_PARENT; + } else { + n->name_len = AUDIT_NAME_FULL; + n->type = AUDIT_TYPE_NORMAL; + } handle_path(dentry); audit_copy_inode(n, dentry, inode); } /** - * audit_inode_child - collect inode info for created/removed objects - * @dentry: dentry being audited + * __audit_inode_child - collect inode info for created/removed objects * @parent: inode of dentry parent + * @dentry: dentry being audited + * @type: AUDIT_TYPE_* value that we're looking for * * For syscalls that create or remove filesystem objects, audit_inode * can only collect information for the filesystem object's parent. @@ -2174,15 +2249,14 @@ out: * must be hooked prior, in order to capture the target inode during * unsuccessful attempts. */ -void __audit_inode_child(const struct dentry *dentry, - const struct inode *parent) +void __audit_inode_child(const struct inode *parent, + const struct dentry *dentry, + const unsigned char type) { struct audit_context *context = current->audit_context; - const char *found_parent = NULL, *found_child = NULL; const struct inode *inode = dentry->d_inode; const char *dname = dentry->d_name.name; - struct audit_names *n; - int dirlen = 0; + struct audit_names *n, *found_parent = NULL, *found_child = NULL; if (!context->in_syscall) return; @@ -2190,62 +2264,65 @@ void __audit_inode_child(const struct dentry *dentry, if (inode) handle_one(inode); - /* parent is more likely, look for it first */ + /* look for a parent entry first */ list_for_each_entry(n, &context->names_list, list) { - if (!n->name) + if (!n->name || n->type != AUDIT_TYPE_PARENT) continue; if (n->ino == parent->i_ino && - !audit_compare_dname_path(dname, n->name, &dirlen)) { - n->name_len = dirlen; /* update parent data in place */ - found_parent = n->name; - goto add_names; + !audit_compare_dname_path(dname, n->name->name, n->name_len)) { + found_parent = n; + break; } } - /* no matching parent, look for matching child */ + /* is there a matching child entry? */ list_for_each_entry(n, &context->names_list, list) { - if (!n->name) + /* can only match entries that have a name */ + if (!n->name || n->type != type) continue; - /* strcmp() is the more likely scenario */ - if (!strcmp(dname, n->name) || - !audit_compare_dname_path(dname, n->name, &dirlen)) { - if (inode) - audit_copy_inode(n, NULL, inode); - else - n->ino = (unsigned long)-1; - found_child = n->name; - goto add_names; + /* if we found a parent, make sure this one is a child of it */ + if (found_parent && (n->name != found_parent->name)) + continue; + + if (!strcmp(dname, n->name->name) || + !audit_compare_dname_path(dname, n->name->name, + found_parent ? + found_parent->name_len : + AUDIT_NAME_FULL)) { + found_child = n; + break; } } -add_names: if (!found_parent) { - n = audit_alloc_name(context); + /* create a new, "anonymous" parent record */ + n = audit_alloc_name(context, AUDIT_TYPE_PARENT); if (!n) return; audit_copy_inode(n, NULL, parent); } if (!found_child) { - n = audit_alloc_name(context); - if (!n) + found_child = audit_alloc_name(context, type); + if (!found_child) return; /* Re-use the name belonging to the slot for a matching parent * directory. All names for this context are relinquished in * audit_free_names() */ if (found_parent) { - n->name = found_parent; - n->name_len = AUDIT_NAME_FULL; + found_child->name = found_parent->name; + found_child->name_len = AUDIT_NAME_FULL; /* don't call __putname() */ - n->name_put = false; + found_child->name_put = false; } - - if (inode) - audit_copy_inode(n, NULL, inode); } + if (inode) + audit_copy_inode(found_child, dentry, inode); + else + found_child->ino = (unsigned long)-1; } EXPORT_SYMBOL_GPL(__audit_inode_child); diff --git a/kernel/events/core.c b/kernel/events/core.c index cda3ebd49e86..dbccf83c134d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -372,6 +372,8 @@ void perf_cgroup_switch(struct task_struct *task, int mode) list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->unique_pmu != pmu) + continue; /* ensure we process each cpuctx once */ /* * perf_cgroup_events says at least one @@ -395,9 +397,10 @@ void perf_cgroup_switch(struct task_struct *task, int mode) if (mode & PERF_CGROUP_SWIN) { WARN_ON_ONCE(cpuctx->cgrp); - /* set cgrp before ctxsw in to - * allow event_filter_match() to not - * have to pass task around + /* + * set cgrp before ctxsw in to allow + * event_filter_match() to not have to pass + * task around */ cpuctx->cgrp = perf_cgroup_from_task(task); cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); @@ -4412,7 +4415,7 @@ static void perf_event_task_event(struct perf_task_event *task_event) rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->active_pmu != pmu) + if (cpuctx->unique_pmu != pmu) goto next; perf_event_task_ctx(&cpuctx->ctx, task_event); @@ -4558,7 +4561,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->active_pmu != pmu) + if (cpuctx->unique_pmu != pmu) goto next; perf_event_comm_ctx(&cpuctx->ctx, comm_event); @@ -4754,7 +4757,7 @@ got_name: rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->active_pmu != pmu) + if (cpuctx->unique_pmu != pmu) goto next; perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, vma->vm_flags & VM_EXEC); @@ -5855,8 +5858,8 @@ static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu) cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); - if (cpuctx->active_pmu == old_pmu) - cpuctx->active_pmu = pmu; + if (cpuctx->unique_pmu == old_pmu) + cpuctx->unique_pmu = pmu; } } @@ -5991,7 +5994,7 @@ skip_type: cpuctx->ctx.pmu = pmu; cpuctx->jiffies_interval = 1; INIT_LIST_HEAD(&cpuctx->rotation_list); - cpuctx->active_pmu = pmu; + cpuctx->unique_pmu = pmu; } got_cpu_context: diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 49a77727db42..4e69e24d3d7d 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -148,7 +148,8 @@ static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, * @host_data: Controller private data pointer * * Allocates a legacy irq_domain if irq_base is positive or a linear - * domain otherwise. + * domain otherwise. For the legacy domain, IRQ descriptors will also + * be allocated. * * This is intended to implement the expected behaviour for most * interrupt controllers which is that a linear mapping should @@ -162,11 +163,33 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node, const struct irq_domain_ops *ops, void *host_data) { - if (first_irq > 0) - return irq_domain_add_legacy(of_node, size, first_irq, 0, + if (first_irq > 0) { + int irq_base; + + if (IS_ENABLED(CONFIG_SPARSE_IRQ)) { + /* + * Set the descriptor allocator to search for a + * 1-to-1 mapping, such as irq_alloc_desc_at(). + * Use of_node_to_nid() which is defined to + * numa_node_id() on platforms that have no custom + * implementation. + */ + irq_base = irq_alloc_descs(first_irq, first_irq, size, + of_node_to_nid(of_node)); + if (irq_base < 0) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + first_irq); + irq_base = first_irq; + } + } else + irq_base = first_irq; + + return irq_domain_add_legacy(of_node, size, irq_base, 0, ops, host_data); - else - return irq_domain_add_linear(of_node, size, ops, host_data); + } + + /* A linear domain is the default */ + return irq_domain_add_linear(of_node, size, ops, host_data); } /** diff --git a/kernel/kmod.c b/kernel/kmod.c index 6f99aead66c6..1c317e386831 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -37,6 +37,7 @@ #include <linux/notifier.h> #include <linux/suspend.h> #include <linux/rwsem.h> +#include <linux/ptrace.h> #include <asm/uaccess.h> #include <trace/events/module.h> @@ -221,11 +222,13 @@ static int ____call_usermodehelper(void *data) retval = kernel_execve(sub_info->path, (const char *const *)sub_info->argv, (const char *const *)sub_info->envp); + if (!retval) + return 0; /* Exec failed? */ fail: sub_info->retval = retval; - return 0; + do_exit(0); } static int call_helper(void *data) @@ -292,7 +295,7 @@ static int wait_for_helper(void *data) } umh_complete(sub_info); - return 0; + do_exit(0); } /* This is run by khelper thread */ diff --git a/kernel/kthread.c b/kernel/kthread.c index 146a6fa96825..29fb60caecb5 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -16,6 +16,7 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <linux/freezer.h> +#include <linux/ptrace.h> #include <trace/events/sched.h> static DEFINE_SPINLOCK(kthread_create_lock); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4fb2376ddf06..74df86bd9204 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -74,6 +74,7 @@ static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS]; .orphan_nxttail = &sname##_state.orphan_nxtlist, \ .orphan_donetail = &sname##_state.orphan_donelist, \ .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \ + .onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \ .name = #sname, \ } @@ -1197,7 +1198,7 @@ static int rcu_gp_init(struct rcu_state *rsp) raw_spin_unlock_irq(&rnp->lock); /* Exclude any concurrent CPU-hotplug operations. */ - get_online_cpus(); + mutex_lock(&rsp->onoff_mutex); /* * Set the quiescent-state-needed bits in all the rcu_node @@ -1234,7 +1235,7 @@ static int rcu_gp_init(struct rcu_state *rsp) cond_resched(); } - put_online_cpus(); + mutex_unlock(&rsp->onoff_mutex); return 1; } @@ -1700,6 +1701,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) /* Remove the dead CPU from the bitmasks in the rcu_node hierarchy. */ /* Exclude any attempts to start a new grace period. */ + mutex_lock(&rsp->onoff_mutex); raw_spin_lock_irqsave(&rsp->onofflock, flags); /* Orphan the dead CPU's callbacks, and adopt them if appropriate. */ @@ -1744,6 +1746,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) init_callback_list(rdp); /* Disallow further callbacks on this CPU. */ rdp->nxttail[RCU_NEXT_TAIL] = NULL; + mutex_unlock(&rsp->onoff_mutex); } #else /* #ifdef CONFIG_HOTPLUG_CPU */ @@ -2648,6 +2651,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_node *rnp = rcu_get_root(rsp); + /* Exclude new grace periods. */ + mutex_lock(&rsp->onoff_mutex); + /* Set up local state, ensuring consistent view of global state. */ raw_spin_lock_irqsave(&rnp->lock, flags); rdp->beenonline = 1; /* We have now been online. */ @@ -2662,14 +2668,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) rcu_prepare_for_idle_init(cpu); raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ - /* - * A new grace period might start here. If so, we won't be part - * of it, but that is OK, as we are currently in a quiescent state. - */ - - /* Exclude any attempts to start a new GP on large systems. */ - raw_spin_lock(&rsp->onofflock); /* irqs already disabled. */ - /* Add CPU to rcu_node bitmasks. */ rnp = rdp->mynode; mask = rdp->grpmask; @@ -2693,8 +2691,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) raw_spin_unlock(&rnp->lock); /* irqs already disabled. */ rnp = rnp->parent; } while (rnp != NULL && !(rnp->qsmaskinit & mask)); + local_irq_restore(flags); - raw_spin_unlock_irqrestore(&rsp->onofflock, flags); + mutex_unlock(&rsp->onoff_mutex); } static void __cpuinit rcu_prepare_cpu(int cpu) diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 5faf05d68326..a240f032848e 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -394,11 +394,17 @@ struct rcu_state { struct rcu_head **orphan_donetail; /* Tail of above. */ long qlen_lazy; /* Number of lazy callbacks. */ long qlen; /* Total number of callbacks. */ + /* End of fields guarded by onofflock. */ + + struct mutex onoff_mutex; /* Coordinate hotplug & GPs. */ + struct mutex barrier_mutex; /* Guards barrier fields. */ atomic_t barrier_cpu_count; /* # CPUs waiting on. */ struct completion barrier_completion; /* Wake at barrier end. */ unsigned long n_barrier_done; /* ++ at start and end of */ /* _rcu_barrier(). */ + /* End of fields guarded by barrier_mutex. */ + unsigned long jiffies_force_qs; /* Time at which to invoke */ /* force_quiescent_state(). */ unsigned long n_force_qs; /* Number of calls to */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c17747236438..2d8927fda712 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -505,7 +505,7 @@ static inline void init_hrtick(void) #ifdef CONFIG_SMP #ifndef tsk_is_polling -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) +#define tsk_is_polling(t) 0 #endif void resched_task(struct task_struct *p) @@ -6122,6 +6122,17 @@ static void sched_init_numa(void) * numbers. */ + /* + * Here, we should temporarily reset sched_domains_numa_levels to 0. + * If it fails to allocate memory for array sched_domains_numa_masks[][], + * the array will contain less then 'level' members. This could be + * dangerous when we use it to iterate array sched_domains_numa_masks[][] + * in other functions. + * + * We reset it to 'level' at the end of this function. + */ + sched_domains_numa_levels = 0; + sched_domains_numa_masks = kzalloc(sizeof(void *) * level, GFP_KERNEL); if (!sched_domains_numa_masks) return; @@ -6176,11 +6187,68 @@ static void sched_init_numa(void) } sched_domain_topology = tl; + + sched_domains_numa_levels = level; +} + +static void sched_domains_numa_masks_set(int cpu) +{ + int i, j; + int node = cpu_to_node(cpu); + + for (i = 0; i < sched_domains_numa_levels; i++) { + for (j = 0; j < nr_node_ids; j++) { + if (node_distance(j, node) <= sched_domains_numa_distance[i]) + cpumask_set_cpu(cpu, sched_domains_numa_masks[i][j]); + } + } +} + +static void sched_domains_numa_masks_clear(int cpu) +{ + int i, j; + for (i = 0; i < sched_domains_numa_levels; i++) { + for (j = 0; j < nr_node_ids; j++) + cpumask_clear_cpu(cpu, sched_domains_numa_masks[i][j]); + } +} + +/* + * Update sched_domains_numa_masks[level][node] array when new cpus + * are onlined. + */ +static int sched_domains_numa_masks_update(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + int cpu = (long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + sched_domains_numa_masks_set(cpu); + break; + + case CPU_DEAD: + sched_domains_numa_masks_clear(cpu); + break; + + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; } #else static inline void sched_init_numa(void) { } + +static int sched_domains_numa_masks_update(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + return 0; +} #endif /* CONFIG_NUMA */ static int __sdt_alloc(const struct cpumask *cpu_map) @@ -6629,6 +6697,7 @@ void __init sched_init_smp(void) mutex_unlock(&sched_domains_mutex); put_online_cpus(); + hotcpu_notifier(sched_domains_numa_masks_update, CPU_PRI_SCHED_ACTIVE); hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE); hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE); diff --git a/kernel/time.c b/kernel/time.c index ba744cf80696..d226c6a3fd28 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -30,7 +30,7 @@ #include <linux/export.h> #include <linux/timex.h> #include <linux/capability.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/errno.h> #include <linux/syscalls.h> #include <linux/security.h> diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index fd42bd452b75..8601f0db1261 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -16,6 +16,10 @@ config ARCH_CLOCKSOURCE_DATA config GENERIC_TIME_VSYSCALL bool +# Timekeeping vsyscall support +config GENERIC_TIME_VSYSCALL_OLD + bool + # ktime_t scalar 64bit nsec representation config KTIME_SCALAR bool diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index aa27d391bfc8..f11d83b12949 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -37,7 +37,6 @@ static struct alarm_base { spinlock_t lock; struct timerqueue_head timerqueue; - struct hrtimer timer; ktime_t (*gettime)(void); clockid_t base_clockid; } alarm_bases[ALARM_NUMTYPE]; @@ -46,6 +45,8 @@ static struct alarm_base { static ktime_t freezer_delta; static DEFINE_SPINLOCK(freezer_delta_lock); +static struct wakeup_source *ws; + #ifdef CONFIG_RTC_CLASS /* rtc timer and device for setting alarm wakeups at suspend */ static struct rtc_timer rtctimer; @@ -130,50 +131,35 @@ static inline void alarmtimer_rtc_timer_init(void) { } * @base: pointer to the base where the timer is being run * @alarm: pointer to alarm being enqueued. * - * Adds alarm to a alarm_base timerqueue and if necessary sets - * an hrtimer to run. + * Adds alarm to a alarm_base timerqueue * * Must hold base->lock when calling. */ static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) { + if (alarm->state & ALARMTIMER_STATE_ENQUEUED) + timerqueue_del(&base->timerqueue, &alarm->node); + timerqueue_add(&base->timerqueue, &alarm->node); alarm->state |= ALARMTIMER_STATE_ENQUEUED; - - if (&alarm->node == timerqueue_getnext(&base->timerqueue)) { - hrtimer_try_to_cancel(&base->timer); - hrtimer_start(&base->timer, alarm->node.expires, - HRTIMER_MODE_ABS); - } } /** - * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue + * alarmtimer_dequeue - Removes an alarm timer from an alarm_base timerqueue * @base: pointer to the base where the timer is running * @alarm: pointer to alarm being removed * - * Removes alarm to a alarm_base timerqueue and if necessary sets - * a new timer to run. + * Removes alarm to a alarm_base timerqueue * * Must hold base->lock when calling. */ -static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) +static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm) { - struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue); - if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED)) return; timerqueue_del(&base->timerqueue, &alarm->node); alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; - - if (next == &alarm->node) { - hrtimer_try_to_cancel(&base->timer); - next = timerqueue_getnext(&base->timerqueue); - if (!next) - return; - hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS); - } } @@ -188,42 +174,23 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) */ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) { - struct alarm_base *base = container_of(timer, struct alarm_base, timer); - struct timerqueue_node *next; + struct alarm *alarm = container_of(timer, struct alarm, timer); + struct alarm_base *base = &alarm_bases[alarm->type]; unsigned long flags; - ktime_t now; int ret = HRTIMER_NORESTART; int restart = ALARMTIMER_NORESTART; spin_lock_irqsave(&base->lock, flags); - now = base->gettime(); - while ((next = timerqueue_getnext(&base->timerqueue))) { - struct alarm *alarm; - ktime_t expired = next->expires; - - if (expired.tv64 > now.tv64) - break; - - alarm = container_of(next, struct alarm, node); - - timerqueue_del(&base->timerqueue, &alarm->node); - alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; - - alarm->state |= ALARMTIMER_STATE_CALLBACK; - spin_unlock_irqrestore(&base->lock, flags); - if (alarm->function) - restart = alarm->function(alarm, now); - spin_lock_irqsave(&base->lock, flags); - alarm->state &= ~ALARMTIMER_STATE_CALLBACK; + alarmtimer_dequeue(base, alarm); + spin_unlock_irqrestore(&base->lock, flags); - if (restart != ALARMTIMER_NORESTART) { - timerqueue_add(&base->timerqueue, &alarm->node); - alarm->state |= ALARMTIMER_STATE_ENQUEUED; - } - } + if (alarm->function) + restart = alarm->function(alarm, base->gettime()); - if (next) { - hrtimer_set_expires(&base->timer, next->expires); + spin_lock_irqsave(&base->lock, flags); + if (restart != ALARMTIMER_NORESTART) { + hrtimer_set_expires(&alarm->timer, alarm->node.expires); + alarmtimer_enqueue(base, alarm); ret = HRTIMER_RESTART; } spin_unlock_irqrestore(&base->lock, flags); @@ -250,6 +217,7 @@ static int alarmtimer_suspend(struct device *dev) unsigned long flags; struct rtc_device *rtc; int i; + int ret; spin_lock_irqsave(&freezer_delta_lock, flags); min = freezer_delta; @@ -279,8 +247,10 @@ static int alarmtimer_suspend(struct device *dev) if (min.tv64 == 0) return 0; - /* XXX - Should we enforce a minimum sleep time? */ - WARN_ON(min.tv64 < NSEC_PER_SEC); + if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) { + __pm_wakeup_event(ws, 2 * MSEC_PER_SEC); + return -EBUSY; + } /* Setup an rtc timer to fire that far in the future */ rtc_timer_cancel(rtc, &rtctimer); @@ -288,9 +258,11 @@ static int alarmtimer_suspend(struct device *dev) now = rtc_tm_to_ktime(tm); now = ktime_add(now, min); - rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); - - return 0; + /* Set alarm, if in the past reject suspend briefly to handle */ + ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); + if (ret < 0) + __pm_wakeup_event(ws, MSEC_PER_SEC); + return ret; } #else static int alarmtimer_suspend(struct device *dev) @@ -324,6 +296,9 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, enum alarmtimer_restart (*function)(struct alarm *, ktime_t)) { timerqueue_init(&alarm->node); + hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid, + HRTIMER_MODE_ABS); + alarm->timer.function = alarmtimer_fired; alarm->function = function; alarm->type = type; alarm->state = ALARMTIMER_STATE_INACTIVE; @@ -334,17 +309,19 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, * @alarm: ptr to alarm to set * @start: time to run the alarm */ -void alarm_start(struct alarm *alarm, ktime_t start) +int alarm_start(struct alarm *alarm, ktime_t start) { struct alarm_base *base = &alarm_bases[alarm->type]; unsigned long flags; + int ret; spin_lock_irqsave(&base->lock, flags); - if (alarmtimer_active(alarm)) - alarmtimer_remove(base, alarm); alarm->node.expires = start; alarmtimer_enqueue(base, alarm); + ret = hrtimer_start(&alarm->timer, alarm->node.expires, + HRTIMER_MODE_ABS); spin_unlock_irqrestore(&base->lock, flags); + return ret; } /** @@ -358,18 +335,12 @@ int alarm_try_to_cancel(struct alarm *alarm) { struct alarm_base *base = &alarm_bases[alarm->type]; unsigned long flags; - int ret = -1; - spin_lock_irqsave(&base->lock, flags); - - if (alarmtimer_callback_running(alarm)) - goto out; + int ret; - if (alarmtimer_is_queued(alarm)) { - alarmtimer_remove(base, alarm); - ret = 1; - } else - ret = 0; -out: + spin_lock_irqsave(&base->lock, flags); + ret = hrtimer_try_to_cancel(&alarm->timer); + if (ret >= 0) + alarmtimer_dequeue(base, alarm); spin_unlock_irqrestore(&base->lock, flags); return ret; } @@ -802,10 +773,6 @@ static int __init alarmtimer_init(void) for (i = 0; i < ALARM_NUMTYPE; i++) { timerqueue_init_head(&alarm_bases[i].timerqueue); spin_lock_init(&alarm_bases[i].lock); - hrtimer_init(&alarm_bases[i].timer, - alarm_bases[i].base_clockid, - HRTIMER_MODE_ABS); - alarm_bases[i].timer.function = alarmtimer_fired; } error = alarmtimer_rtc_interface_setup(); @@ -821,6 +788,7 @@ static int __init alarmtimer_init(void) error = PTR_ERR(pdev); goto out_drv; } + ws = wakeup_source_register("alarmtimer"); return 0; out_drv: diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index 46da0537c10b..6629bf7b5285 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -37,7 +37,7 @@ * requested HZ value. It is also not recommended * for "tick-less" systems. */ -#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/SHIFTED_HZ)) +#define NSEC_PER_JIFFY ((NSEC_PER_SEC+HZ/2)/HZ) /* Since jiffies uses a simple NSEC_PER_JIFFY multiplier * conversion, the .shift value could be zero. However @@ -95,3 +95,33 @@ struct clocksource * __init __weak clocksource_default_clock(void) { return &clocksource_jiffies; } + +struct clocksource refined_jiffies; + +int register_refined_jiffies(long cycles_per_second) +{ + u64 nsec_per_tick, shift_hz; + long cycles_per_tick; + + + + refined_jiffies = clocksource_jiffies; + refined_jiffies.name = "refined-jiffies"; + refined_jiffies.rating++; + + /* Calc cycles per tick */ + cycles_per_tick = (cycles_per_second + HZ/2)/HZ; + /* shift_hz stores hz<<8 for extra accuracy */ + shift_hz = (u64)cycles_per_second << 8; + shift_hz += cycles_per_tick/2; + do_div(shift_hz, cycles_per_tick); + /* Calculate nsec_per_tick using shift_hz */ + nsec_per_tick = (u64)NSEC_PER_SEC << 8; + nsec_per_tick += (u32)shift_hz/2; + do_div(nsec_per_tick, (u32)shift_hz); + + refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT; + + clocksource_register(&refined_jiffies); + return 0; +} diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index f423bdd035c2..a40260885265 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -835,7 +835,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) */ if (ts->tick_stopped) { touch_softlockup_watchdog(); - if (idle_cpu(cpu)) + if (is_idle_task(current)) ts->idle_jiffies++; } update_process_times(user_mode(regs)); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 5ce06a3fa91e..e424970bb562 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -8,6 +8,7 @@ * */ +#include <linux/timekeeper_internal.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/percpu.h> @@ -21,61 +22,6 @@ #include <linux/tick.h> #include <linux/stop_machine.h> -/* Structure holding internal timekeeping values. */ -struct timekeeper { - /* Current clocksource used for timekeeping. */ - struct clocksource *clock; - /* NTP adjusted clock multiplier */ - u32 mult; - /* The shift value of the current clocksource. */ - u32 shift; - /* Number of clock cycles in one NTP interval. */ - cycle_t cycle_interval; - /* Number of clock shifted nano seconds in one NTP interval. */ - u64 xtime_interval; - /* shifted nano seconds left over when rounding cycle_interval */ - s64 xtime_remainder; - /* Raw nano seconds accumulated per NTP interval. */ - u32 raw_interval; - - /* Current CLOCK_REALTIME time in seconds */ - u64 xtime_sec; - /* Clock shifted nano seconds */ - u64 xtime_nsec; - - /* Difference between accumulated time and NTP time in ntp - * shifted nano seconds. */ - s64 ntp_error; - /* Shift conversion between clock shifted nano seconds and - * ntp shifted nano seconds. */ - u32 ntp_error_shift; - - /* - * wall_to_monotonic is what we need to add to xtime (or xtime corrected - * for sub jiffie times) to get to monotonic time. Monotonic is pegged - * at zero at system boot time, so wall_to_monotonic will be negative, - * however, we will ALWAYS keep the tv_nsec part positive so we can use - * the usual normalization. - * - * wall_to_monotonic is moved after resume from suspend for the - * monotonic time not to jump. We need to add total_sleep_time to - * wall_to_monotonic to get the real boot based time offset. - * - * - wall_to_monotonic is no longer the boot time, getboottime must be - * used instead. - */ - struct timespec wall_to_monotonic; - /* Offset clock monotonic -> clock realtime */ - ktime_t offs_real; - /* time spent in suspend */ - struct timespec total_sleep_time; - /* Offset clock monotonic -> clock boottime */ - ktime_t offs_boot; - /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ - struct timespec raw_time; - /* Seqlock for all timekeeper values */ - seqlock_t lock; -}; static struct timekeeper timekeeper; @@ -96,15 +42,6 @@ static inline void tk_normalize_xtime(struct timekeeper *tk) } } -static struct timespec tk_xtime(struct timekeeper *tk) -{ - struct timespec ts; - - ts.tv_sec = tk->xtime_sec; - ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); - return ts; -} - static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts) { tk->xtime_sec = ts->tv_sec; @@ -246,14 +183,11 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) /* must hold write on timekeeper.lock */ static void timekeeping_update(struct timekeeper *tk, bool clearntp) { - struct timespec xt; - if (clearntp) { tk->ntp_error = 0; ntp_clear(); } - xt = tk_xtime(tk); - update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); + update_vsyscall(tk); } /** @@ -1113,7 +1047,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, accumulate_nsecs_to_secs(tk); /* Accumulate raw time */ - raw_nsecs = tk->raw_interval << shift; + raw_nsecs = (u64)tk->raw_interval << shift; raw_nsecs += tk->raw_time.tv_nsec; if (raw_nsecs >= NSEC_PER_SEC) { u64 raw_secs = raw_nsecs; @@ -1130,6 +1064,33 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, return offset; } +#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD +static inline void old_vsyscall_fixup(struct timekeeper *tk) +{ + s64 remainder; + + /* + * Store only full nanoseconds into xtime_nsec after rounding + * it up and add the remainder to the error difference. + * XXX - This is necessary to avoid small 1ns inconsistnecies caused + * by truncating the remainder in vsyscalls. However, it causes + * additional work to be done in timekeeping_adjust(). Once + * the vsyscall implementations are converted to use xtime_nsec + * (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD + * users are removed, this can be killed. + */ + remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); + tk->xtime_nsec -= remainder; + tk->xtime_nsec += 1ULL << tk->shift; + tk->ntp_error += remainder << tk->ntp_error_shift; + +} +#else +#define old_vsyscall_fixup(tk) +#endif + + + /** * update_wall_time - Uses the current clocksource to increment the wall time * @@ -1141,7 +1102,6 @@ static void update_wall_time(void) cycle_t offset; int shift = 0, maxshift; unsigned long flags; - s64 remainder; write_seqlock_irqsave(&tk->lock, flags); @@ -1183,20 +1143,11 @@ static void update_wall_time(void) /* correct the clock when NTP error is too big */ timekeeping_adjust(tk, offset); - /* - * Store only full nanoseconds into xtime_nsec after rounding - * it up and add the remainder to the error difference. - * XXX - This is necessary to avoid small 1ns inconsistnecies caused - * by truncating the remainder in vsyscalls. However, it causes - * additional work to be done in timekeeping_adjust(). Once - * the vsyscall implementations are converted to use xtime_nsec - * (shifted nanoseconds), this can be killed. - */ - remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); - tk->xtime_nsec -= remainder; - tk->xtime_nsec += 1ULL << tk->shift; - tk->ntp_error += remainder << tk->ntp_error_shift; + * XXX This can be killed once everyone converts + * to the new update_vsyscall. + */ + old_vsyscall_fixup(tk); /* * Finally, make sure that after the rounding diff --git a/kernel/timer.c b/kernel/timer.c index d5de1b2292aa..367d00858482 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -63,6 +63,7 @@ EXPORT_SYMBOL(jiffies_64); #define TVR_SIZE (1 << TVR_BITS) #define TVN_MASK (TVN_SIZE - 1) #define TVR_MASK (TVR_SIZE - 1) +#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) struct tvec { struct list_head vec[TVN_SIZE]; @@ -359,11 +360,12 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer) vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK); } else { int i; - /* If the timeout is larger than 0xffffffff on 64-bit - * architectures then we use the maximum timeout: + /* If the timeout is larger than MAX_TVAL (on 64-bit + * architectures or with CONFIG_BASE_SMALL=1) then we + * use the maximum timeout. */ - if (idx > 0xffffffffUL) { - idx = 0xffffffffUL; + if (idx > MAX_TVAL) { + idx = MAX_TVAL; expires = idx + base->timer_jiffies; } i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; diff --git a/lib/kasprintf.c b/lib/kasprintf.c index ae0de80c1c88..32f12150fc4f 100644 --- a/lib/kasprintf.c +++ b/lib/kasprintf.c @@ -21,7 +21,7 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap) len = vsnprintf(NULL, 0, fmt, aq); va_end(aq); - p = kmalloc(len+1, gfp); + p = kmalloc_track_caller(len+1, gfp); if (!p) return NULL; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index b41823cc05e6..d3ca2b3ee176 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -158,16 +158,16 @@ static ssize_t read_ahead_kb_store(struct device *dev, const char *buf, size_t count) { struct backing_dev_info *bdi = dev_get_drvdata(dev); - char *end; unsigned long read_ahead_kb; - ssize_t ret = -EINVAL; + ssize_t ret; - read_ahead_kb = simple_strtoul(buf, &end, 10); - if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) { - bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10); - ret = count; - } - return ret; + ret = kstrtoul(buf, 10, &read_ahead_kb); + if (ret < 0) + return ret; + + bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10); + + return count; } #define K(pages) ((pages) << (PAGE_SHIFT - 10)) @@ -187,16 +187,17 @@ static ssize_t min_ratio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct backing_dev_info *bdi = dev_get_drvdata(dev); - char *end; unsigned int ratio; - ssize_t ret = -EINVAL; + ssize_t ret; + + ret = kstrtouint(buf, 10, &ratio); + if (ret < 0) + return ret; + + ret = bdi_set_min_ratio(bdi, ratio); + if (!ret) + ret = count; - ratio = simple_strtoul(buf, &end, 10); - if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) { - ret = bdi_set_min_ratio(bdi, ratio); - if (!ret) - ret = count; - } return ret; } BDI_SHOW(min_ratio, bdi->min_ratio) @@ -205,16 +206,17 @@ static ssize_t max_ratio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct backing_dev_info *bdi = dev_get_drvdata(dev); - char *end; unsigned int ratio; - ssize_t ret = -EINVAL; + ssize_t ret; + + ret = kstrtouint(buf, 10, &ratio); + if (ret < 0) + return ret; + + ret = bdi_set_max_ratio(bdi, ratio); + if (!ret) + ret = count; - ratio = simple_strtoul(buf, &end, 10); - if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) { - ret = bdi_set_max_ratio(bdi, ratio); - if (!ret) - ret = count; - } return ret; } BDI_SHOW(max_ratio, bdi->max_ratio) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 5ad5ce23c1e0..830893b2b3c7 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1602,10 +1602,18 @@ void writeback_set_ratelimit(void) } static int __cpuinit -ratelimit_handler(struct notifier_block *self, unsigned long u, void *v) +ratelimit_handler(struct notifier_block *self, unsigned long action, + void *hcpu) { - writeback_set_ratelimit(); - return NOTIFY_DONE; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + case CPU_DEAD: + writeback_set_ratelimit(); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } } static struct notifier_block __cpuinitdata ratelimit_nb = { diff --git a/mm/shmem.c b/mm/shmem.c index cc12072f8787..67afba5117f2 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2220,12 +2220,14 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, { struct inode *inode; struct dentry *dentry = NULL; - u64 inum = fid->raw[2]; - inum = (inum << 32) | fid->raw[1]; + u64 inum; if (fh_len < 3) return NULL; + inum = fid->raw[2]; + inum = (inum << 32) | fid->raw[1]; + inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]), shmem_match, fid->raw); if (inode) { diff --git a/mm/slab_common.c b/mm/slab_common.c index 9c217255ac49..069a24e64403 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -168,6 +168,7 @@ void kmem_cache_destroy(struct kmem_cache *s) list_del(&s->list); if (!__kmem_cache_shutdown(s)) { + mutex_unlock(&slab_mutex); if (s->flags & SLAB_DESTROY_BY_RCU) rcu_barrier(); @@ -175,12 +176,14 @@ void kmem_cache_destroy(struct kmem_cache *s) kmem_cache_free(kmem_cache, s); } else { list_add(&s->list, &slab_caches); + mutex_unlock(&slab_mutex); printk(KERN_ERR "kmem_cache_destroy %s: Slab cache still has objects\n", s->name); dump_stack(); } + } else { + mutex_unlock(&slab_mutex); } - mutex_unlock(&slab_mutex); put_online_cpus(); } EXPORT_SYMBOL(kmem_cache_destroy); diff --git a/mm/swapfile.c b/mm/swapfile.c index 14e254c768fc..71cd288b2001 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1483,7 +1483,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) struct file *swap_file, *victim; struct address_space *mapping; struct inode *inode; - char *pathname; + struct filename *pathname; int oom_score_adj; int i, type, prev; int err; @@ -1498,8 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(pathname)) goto out; - victim = filp_open(pathname, O_RDWR|O_LARGEFILE, 0); - putname(pathname); + victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); if (IS_ERR(victim)) goto out; @@ -1936,7 +1935,7 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; - char *name; + struct filename *name; struct file *swap_file = NULL; struct address_space *mapping; int i; @@ -1967,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) name = NULL; goto bad_swap; } - swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0); + swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(swap_file)) { error = PTR_ERR(swap_file); swap_file = NULL; @@ -2053,7 +2052,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) printk(KERN_INFO "Adding %uk swap on %s. " "Priority:%d extents:%d across:%lluk %s%s%s\n", - p->pages<<(PAGE_SHIFT-10), name, p->prio, + p->pages<<(PAGE_SHIFT-10), name->name, p->prio, nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), (p->flags & SWP_SOLIDSTATE) ? "SS" : "", (p->flags & SWP_DISCARDABLE) ? "D" : "", diff --git a/net/9p/client.c b/net/9p/client.c index 8260f132b32e..34d417670935 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -76,6 +76,20 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) } EXPORT_SYMBOL(p9_is_proto_dotu); +/* + * Some error codes are taken directly from the server replies, + * make sure they are valid. + */ +static int safe_errno(int err) +{ + if ((err > 0) || (err < -MAX_ERRNO)) { + p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err); + return -EPROTO; + } + return err; +} + + /* Interpret mount option for protocol version */ static int get_protocol_version(char *s) { @@ -782,7 +796,7 @@ again: return req; reterr: p9_free_req(c, req); - return ERR_PTR(err); + return ERR_PTR(safe_errno(err)); } /** @@ -865,7 +879,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, return req; reterr: p9_free_req(c, req); - return ERR_PTR(err); + return ERR_PTR(safe_errno(err)); } static struct p9_fid *p9_fid_create(struct p9_client *clnt) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 15656b8573f3..02efb25c2957 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -316,8 +316,7 @@ static void p9_read_work(struct work_struct *work) m->rsize - m->rpos); p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); if (err == -EAGAIN) { - clear_bit(Rworksched, &m->wsched); - return; + goto end_clear; } if (err <= 0) @@ -379,19 +378,20 @@ static void p9_read_work(struct work_struct *work) m->req = NULL; } +end_clear: + clear_bit(Rworksched, &m->wsched); + if (!list_empty(&m->req_list)) { if (test_and_clear_bit(Rpending, &m->wsched)) n = POLLIN; else n = p9_fd_poll(m->client, NULL); - if (n & POLLIN) { + if ((n & POLLIN) && !test_and_set_bit(Rworksched, &m->wsched)) { p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m); schedule_work(&m->rq); - } else - clear_bit(Rworksched, &m->wsched); - } else - clear_bit(Rworksched, &m->wsched); + } + } return; error: @@ -453,12 +453,13 @@ static void p9_write_work(struct work_struct *work) } if (!m->wsize) { + spin_lock(&m->client->lock); if (list_empty(&m->unsent_req_list)) { clear_bit(Wworksched, &m->wsched); + spin_unlock(&m->client->lock); return; } - spin_lock(&m->client->lock); req = list_entry(m->unsent_req_list.next, struct p9_req_t, req_list); req->status = REQ_STATUS_SENT; @@ -476,10 +477,9 @@ static void p9_write_work(struct work_struct *work) clear_bit(Wpending, &m->wsched); err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); - if (err == -EAGAIN) { - clear_bit(Wworksched, &m->wsched); - return; - } + if (err == -EAGAIN) + goto end_clear; + if (err < 0) goto error; @@ -492,19 +492,21 @@ static void p9_write_work(struct work_struct *work) if (m->wpos == m->wsize) m->wpos = m->wsize = 0; - if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { +end_clear: + clear_bit(Wworksched, &m->wsched); + + if (m->wsize || !list_empty(&m->unsent_req_list)) { if (test_and_clear_bit(Wpending, &m->wsched)) n = POLLOUT; else n = p9_fd_poll(m->client, NULL); - if (n & POLLOUT) { + if ((n & POLLOUT) && + !test_and_set_bit(Wworksched, &m->wsched)) { p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m); schedule_work(&m->wq); - } else - clear_bit(Wworksched, &m->wsched); - } else - clear_bit(Wworksched, &m->wsched); + } + } return; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 68e8f364bbf8..fe43bc7b063f 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -265,6 +265,9 @@ static int br_parse_ip_options(struct sk_buff *skb) struct net_device *dev = skb->dev; u32 len; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto inhdr_error; + iph = ip_hdr(skb); opt = &(IPCB(skb)->opt); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 148e73d2c451..d1dc14c2aac4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -248,8 +248,8 @@ struct pktgen_dev { int removal_mark; /* non-zero => the device is marked for * removal by worker thread */ - int min_pkt_size; /* = ETH_ZLEN; */ - int max_pkt_size; /* = ETH_ZLEN; */ + int min_pkt_size; + int max_pkt_size; int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ int nfrags; struct page *page; @@ -449,8 +449,6 @@ static void pktgen_stop_all_threads_ifs(void); static void pktgen_stop(struct pktgen_thread *t); static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); -static unsigned int scan_ip6(const char *s, char ip[16]); - /* Module parameters, defaults. */ static int pg_count_d __read_mostly = 1000; static int pg_delay_d __read_mostly; @@ -702,8 +700,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v) &pkt_dev->cur_in6_saddr, &pkt_dev->cur_in6_daddr); } else - seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", - pkt_dev->cur_saddr, pkt_dev->cur_daddr); + seq_printf(seq, " cur_saddr: %pI4 cur_daddr: %pI4\n", + &pkt_dev->cur_saddr, &pkt_dev->cur_daddr); seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); @@ -1299,7 +1297,7 @@ static ssize_t pktgen_if_write(struct file *file, return -EFAULT; buf[len] = 0; - scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); + in6_pton(buf, -1, pkt_dev->in6_daddr.s6_addr, -1, NULL); snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr; @@ -1322,7 +1320,7 @@ static ssize_t pktgen_if_write(struct file *file, return -EFAULT; buf[len] = 0; - scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); + in6_pton(buf, -1, pkt_dev->min_in6_daddr.s6_addr, -1, NULL); snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr; @@ -1344,7 +1342,7 @@ static ssize_t pktgen_if_write(struct file *file, return -EFAULT; buf[len] = 0; - scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); + in6_pton(buf, -1, pkt_dev->max_in6_daddr.s6_addr, -1, NULL); snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); if (debug) @@ -1365,7 +1363,7 @@ static ssize_t pktgen_if_write(struct file *file, return -EFAULT; buf[len] = 0; - scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); + in6_pton(buf, -1, pkt_dev->in6_saddr.s6_addr, -1, NULL); snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr; @@ -2036,19 +2034,17 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) /* Set up Dest MAC */ memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); - /* Set up pkt size */ - pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; - if (pkt_dev->flags & F_IPV6) { - /* - * Skip this automatic address setting until locks or functions - * gets exported - */ - -#ifdef NOTNOW int i, set = 0, err = 1; struct inet6_dev *idev; + if (pkt_dev->min_pkt_size == 0) { + pkt_dev->min_pkt_size = 14 + sizeof(struct ipv6hdr) + + sizeof(struct udphdr) + + sizeof(struct pktgen_hdr) + + pkt_dev->pkt_overhead; + } + for (i = 0; i < IN6_ADDR_HSIZE; i++) if (pkt_dev->cur_in6_saddr.s6_addr[i]) { set = 1; @@ -2069,9 +2065,8 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); - for (ifp = idev->addr_list; ifp; - ifp = ifp->if_next) { - if (ifp->scope == IFA_LINK && + list_for_each_entry(ifp, &idev->addr_list, if_list) { + if ((ifp->scope & IFA_LINK) && !(ifp->flags & IFA_F_TENTATIVE)) { pkt_dev->cur_in6_saddr = ifp->addr; err = 0; @@ -2084,8 +2079,14 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) if (err) pr_err("ERROR: IPv6 link address not available\n"); } -#endif } else { + if (pkt_dev->min_pkt_size == 0) { + pkt_dev->min_pkt_size = 14 + sizeof(struct iphdr) + + sizeof(struct udphdr) + + sizeof(struct pktgen_hdr) + + pkt_dev->pkt_overhead; + } + pkt_dev->saddr_min = 0; pkt_dev->saddr_max = 0; if (strlen(pkt_dev->src_min) == 0) { @@ -2111,6 +2112,10 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); } /* Initialize current values. */ + pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; + if (pkt_dev->min_pkt_size > pkt_dev->max_pkt_size) + pkt_dev->max_pkt_size = pkt_dev->min_pkt_size; + pkt_dev->cur_dst_mac_offset = 0; pkt_dev->cur_src_mac_offset = 0; pkt_dev->cur_saddr = pkt_dev->saddr_min; @@ -2758,97 +2763,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, return skb; } -/* - * scan_ip6, fmt_ip taken from dietlibc-0.21 - * Author Felix von Leitner <felix-dietlibc@fefe.de> - * - * Slightly modified for kernel. - * Should be candidate for net/ipv4/utils.c - * --ro - */ - -static unsigned int scan_ip6(const char *s, char ip[16]) -{ - unsigned int i; - unsigned int len = 0; - unsigned long u; - char suffix[16]; - unsigned int prefixlen = 0; - unsigned int suffixlen = 0; - __be32 tmp; - char *pos; - - for (i = 0; i < 16; i++) - ip[i] = 0; - - for (;;) { - if (*s == ':') { - len++; - if (s[1] == ':') { /* Found "::", skip to part 2 */ - s += 2; - len++; - break; - } - s++; - } - - u = simple_strtoul(s, &pos, 16); - i = pos - s; - if (!i) - return 0; - if (prefixlen == 12 && s[i] == '.') { - - /* the last 4 bytes may be written as IPv4 address */ - - tmp = in_aton(s); - memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); - return i + len; - } - ip[prefixlen++] = (u >> 8); - ip[prefixlen++] = (u & 255); - s += i; - len += i; - if (prefixlen == 16) - return len; - } - -/* part 2, after "::" */ - for (;;) { - if (*s == ':') { - if (suffixlen == 0) - break; - s++; - len++; - } else if (suffixlen != 0) - break; - - u = simple_strtol(s, &pos, 16); - i = pos - s; - if (!i) { - if (*s) - len--; - break; - } - if (suffixlen + prefixlen <= 12 && s[i] == '.') { - tmp = in_aton(s); - memcpy((struct in_addr *)(suffix + suffixlen), &tmp, - sizeof(tmp)); - suffixlen += 4; - len += strlen(s); - break; - } - suffix[suffixlen++] = (u >> 8); - suffix[suffixlen++] = (u & 255); - s += i; - len += i; - if (prefixlen + suffixlen == 16) - break; - } - for (i = 0; i < suffixlen; i++) - ip[16 - suffixlen + i] = suffix[i]; - return len; -} - static struct sk_buff *fill_packet_ipv6(struct net_device *odev, struct pktgen_dev *pkt_dev) { @@ -2927,7 +2841,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, sizeof(struct ipv6hdr) - sizeof(struct udphdr) - pkt_dev->pkt_overhead; - if (datalen < sizeof(struct pktgen_hdr)) { + if (datalen < 0 || datalen < sizeof(struct pktgen_hdr)) { datalen = sizeof(struct pktgen_hdr); net_info_ratelimited("increased datalen to %d\n", datalen); } @@ -3548,8 +3462,6 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) } pkt_dev->removal_mark = 0; - pkt_dev->min_pkt_size = ETH_ZLEN; - pkt_dev->max_pkt_size = ETH_ZLEN; pkt_dev->nfrags = 0; pkt_dev->delay = pg_delay_d; pkt_dev->count = pg_count_d; diff --git a/net/core/utils.c b/net/core/utils.c index f5613d569c23..e3487e461939 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -107,6 +107,18 @@ static inline int xdigit2bin(char c, int delim) return IN6PTON_UNKNOWN; } +/** + * in4_pton - convert an IPv4 address from literal to binary representation + * @src: the start of the IPv4 address string + * @srclen: the length of the string, -1 means strlen(src) + * @dst: the binary (u8[4] array) representation of the IPv4 address + * @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter + * @end: A pointer to the end of the parsed string will be placed here + * + * Return one on success, return zero when any error occurs + * and @end will point to the end of the parsed string. + * + */ int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end) @@ -161,6 +173,18 @@ out: } EXPORT_SYMBOL(in4_pton); +/** + * in6_pton - convert an IPv6 address from literal to binary representation + * @src: the start of the IPv6 address string + * @srclen: the length of the string, -1 means strlen(src) + * @dst: the binary (u8[16] array) representation of the IPv6 address + * @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter + * @end: A pointer to the end of the parsed string will be placed here + * + * Return one on success, return zero when any error occurs + * and @end will point to the end of the parsed string. + * + */ int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 978bca4818ae..1831092f999f 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -374,7 +374,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) memset(&fl4, 0, sizeof(fl4)); flowi4_init_output(&fl4, tunnel->parms.link, - htonl(tunnel->parms.i_key), RT_TOS(tos), + be32_to_cpu(tunnel->parms.i_key), RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPIP, 0, dst, tiph->saddr, 0, 0); @@ -441,7 +441,7 @@ static int vti_tunnel_bind_dev(struct net_device *dev) struct flowi4 fl4; memset(&fl4, 0, sizeof(fl4)); flowi4_init_output(&fl4, tunnel->parms.link, - htonl(tunnel->parms.i_key), + be32_to_cpu(tunnel->parms.i_key), RT_TOS(iph->tos), RT_SCOPE_UNIVERSE, IPPROTO_IPIP, 0, iph->daddr, iph->saddr, 0, 0); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 1a0da8dc8180..432f4bb77238 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2220,7 +2220,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, goto nla_put_failure; if (fl4->flowi4_mark && - nla_put_be32(skb, RTA_MARK, fl4->flowi4_mark)) + nla_put_u32(skb, RTA_MARK, fl4->flowi4_mark)) goto nla_put_failure; error = rt->dst.error; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 9205e492dc9d..63d4eccc674d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -248,6 +248,8 @@ int proc_tcp_fastopen_key(ctl_table *ctl, int write, void __user *buffer, ctxt = rcu_dereference(tcp_fastopen_ctx); if (ctxt) memcpy(user_key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); + else + memset(user_key, 0, sizeof(user_key)); rcu_read_unlock(); snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x", diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 75735c9a6a9d..ef998b008a57 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -708,10 +708,11 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; /* When socket is gone, all binding information is lost. - * routing might fail in this case. using iif for oif to - * make sure we can deliver it + * routing might fail in this case. No choice here, if we choose to force + * input interface, we will misroute in case of asymmetric route. */ - arg.bound_dev_if = sk ? sk->sk_bound_dev_if : inet_iif(skb); + if (sk) + arg.bound_dev_if = sk->sk_bound_dev_if; net = dev_net(skb_dst(skb)->dev); arg.tos = ip_hdr(skb)->tos; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 49c890386ce9..26175bffbaa0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -877,7 +877,8 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr); fl6.flowi6_proto = IPPROTO_TCP; - fl6.flowi6_oif = inet6_iif(skb); + if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) + fl6.flowi6_oif = inet6_iif(skb); fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index accfa00ffcdf..a16b7b4b1e02 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -56,7 +56,6 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) u64 tsfdelta; spin_lock_bh(&ifmsh->sync_offset_lock); - if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n", (long long) ifmsh->sync_offset_clockdrift_max); @@ -69,11 +68,11 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) tsfdelta = -beacon_int_fraction; ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction; } + spin_unlock_bh(&ifmsh->sync_offset_lock); tsf = drv_get_tsf(local, sdata); if (tsf != -1ULL) drv_set_tsf(local, sdata, tsf + tsfdelta); - spin_unlock_bh(&ifmsh->sync_offset_lock); } static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2ce89732d0f2..3af0cc4130f1 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -34,7 +34,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, skb_queue_len(&local->skb_queue_unreliable); while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && (skb = skb_dequeue(&local->skb_queue_unreliable))) { - dev_kfree_skb_irq(skb); + ieee80211_free_txskb(hw, skb); tmp--; I802_DEBUG_INC(local->tx_status_drop); } @@ -159,7 +159,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", skb_queue_len(&sta->tx_filtered[ac]), !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); } static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e0e0d1d0e830..c9bf83f36657 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -354,7 +354,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) total += skb_queue_len(&sta->ps_tx_buf[ac]); if (skb) { purged++; - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); break; } } @@ -466,7 +466,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ps_dbg(tx->sdata, "STA %pM TX buffer for AC %d full - dropping oldest frame\n", sta->sta.addr, ac); - dev_kfree_skb(old); + ieee80211_free_txskb(&local->hw, old); } else tx->local->total_ps_buffered++; @@ -1103,7 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, spin_unlock(&tx->sta->lock); if (purge_skb) - dev_kfree_skb(purge_skb); + ieee80211_free_txskb(&tx->local->hw, purge_skb); } /* reset session timer */ @@ -1214,7 +1214,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (WARN_ON_ONCE(q >= local->hw.queues)) { __skb_unlink(skb, skbs); - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); continue; } #endif @@ -1356,7 +1356,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(tx->local->tx_handlers_drop); if (tx->skb) - dev_kfree_skb(tx->skb); + ieee80211_free_txskb(&tx->local->hw, tx->skb); else __skb_queue_purge(&tx->skbs); return -1; @@ -1393,7 +1393,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); if (unlikely(res_prepare == TX_DROP)) { - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); goto out; } else if (unlikely(res_prepare == TX_QUEUED)) { goto out; @@ -1465,7 +1465,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) headroom = max_t(int, 0, headroom); if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); rcu_read_unlock(); return; } @@ -2050,8 +2050,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, head_need += IEEE80211_ENCRYPT_HEADROOM; head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); - if (ieee80211_skb_resize(sdata, skb, head_need, true)) - goto fail; + if (ieee80211_skb_resize(sdata, skb, head_need, true)) { + ieee80211_free_txskb(&local->hw, skb); + return NETDEV_TX_OK; + } } if (encaps_data) { @@ -2184,7 +2186,7 @@ void ieee80211_tx_pending(unsigned long data) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (WARN_ON(!info->control.vif)) { - kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); continue; } diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index bac973a31367..194d865fae72 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -208,6 +208,35 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); } +/* + * svc_xprt_received conditionally queues the transport for processing + * by another thread. The caller must hold the XPT_BUSY bit and must + * not thereafter touch transport data. + * + * Note: XPT_DATA only gets cleared when a read-attempt finds no (or + * insufficient) data. + */ +static void svc_xprt_received(struct svc_xprt *xprt) +{ + BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); + /* As soon as we clear busy, the xprt could be closed and + * 'put', so we need a reference to call svc_xprt_enqueue with: + */ + svc_xprt_get(xprt); + clear_bit(XPT_BUSY, &xprt->xpt_flags); + svc_xprt_enqueue(xprt); + svc_xprt_put(xprt); +} + +void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) +{ + clear_bit(XPT_TEMP, &new->xpt_flags); + spin_lock_bh(&serv->sv_lock); + list_add(&new->xpt_list, &serv->sv_permsocks); + spin_unlock_bh(&serv->sv_lock); + svc_xprt_received(new); +} + int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, struct net *net, const int family, const unsigned short port, int flags) @@ -232,13 +261,8 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, module_put(xcl->xcl_owner); return PTR_ERR(newxprt); } - - clear_bit(XPT_TEMP, &newxprt->xpt_flags); - spin_lock_bh(&serv->sv_lock); - list_add(&newxprt->xpt_list, &serv->sv_permsocks); - spin_unlock_bh(&serv->sv_lock); + svc_add_new_perm_xprt(serv, newxprt); newport = svc_xprt_local_port(newxprt); - clear_bit(XPT_BUSY, &newxprt->xpt_flags); return newport; } err: @@ -394,27 +418,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) return xprt; } -/* - * svc_xprt_received conditionally queues the transport for processing - * by another thread. The caller must hold the XPT_BUSY bit and must - * not thereafter touch transport data. - * - * Note: XPT_DATA only gets cleared when a read-attempt finds no (or - * insufficient) data. - */ -void svc_xprt_received(struct svc_xprt *xprt) -{ - BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); - /* As soon as we clear busy, the xprt could be closed and - * 'put', so we need a reference to call svc_xprt_enqueue with: - */ - svc_xprt_get(xprt); - clear_bit(XPT_BUSY, &xprt->xpt_flags); - svc_xprt_enqueue(xprt); - svc_xprt_put(xprt); -} -EXPORT_SYMBOL_GPL(svc_xprt_received); - /** * svc_reserve - change the space reserved for the reply to a request. * @rqstp: The request in question @@ -565,33 +568,12 @@ static void svc_check_conn_limits(struct svc_serv *serv) } } -/* - * Receive the next request on any transport. This code is carefully - * organised not to touch any cachelines in the shared svc_serv - * structure, only cachelines in the local svc_pool. - */ -int svc_recv(struct svc_rqst *rqstp, long timeout) +int svc_alloc_arg(struct svc_rqst *rqstp) { - struct svc_xprt *xprt = NULL; - struct svc_serv *serv = rqstp->rq_server; - struct svc_pool *pool = rqstp->rq_pool; - int len, i; - int pages; - struct xdr_buf *arg; - DECLARE_WAITQUEUE(wait, current); - long time_left; - - dprintk("svc: server %p waiting for data (to = %ld)\n", - rqstp, timeout); - - if (rqstp->rq_xprt) - printk(KERN_ERR - "svc_recv: service %p, transport not NULL!\n", - rqstp); - if (waitqueue_active(&rqstp->rq_wait)) - printk(KERN_ERR - "svc_recv: service %p, wait queue active!\n", - rqstp); + struct svc_serv *serv = rqstp->rq_server; + struct xdr_buf *arg; + int pages; + int i; /* now allocate needed pages. If we get a failure, sleep briefly */ pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; @@ -621,11 +603,15 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) arg->page_len = (pages-2)*PAGE_SIZE; arg->len = (pages-1)*PAGE_SIZE; arg->tail[0].iov_len = 0; + return 0; +} - try_to_freeze(); - cond_resched(); - if (signalled() || kthread_should_stop()) - return -EINTR; +struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout) +{ + struct svc_xprt *xprt; + struct svc_pool *pool = rqstp->rq_pool; + DECLARE_WAITQUEUE(wait, current); + long time_left; /* Normally we will wait up to 5 seconds for any required * cache information to be provided. @@ -663,7 +649,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) if (kthread_should_stop()) { set_current_state(TASK_RUNNING); spin_unlock_bh(&pool->sp_lock); - return -EINTR; + return ERR_PTR(-EINTR); } add_wait_queue(&rqstp->rq_wait, &wait); @@ -684,48 +670,58 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) spin_unlock_bh(&pool->sp_lock); dprintk("svc: server %p, no data yet\n", rqstp); if (signalled() || kthread_should_stop()) - return -EINTR; + return ERR_PTR(-EINTR); else - return -EAGAIN; + return ERR_PTR(-EAGAIN); } } spin_unlock_bh(&pool->sp_lock); + return xprt; +} + +void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt) +{ + spin_lock_bh(&serv->sv_lock); + set_bit(XPT_TEMP, &newxpt->xpt_flags); + list_add(&newxpt->xpt_list, &serv->sv_tempsocks); + serv->sv_tmpcnt++; + if (serv->sv_temptimer.function == NULL) { + /* setup timer to age temp transports */ + setup_timer(&serv->sv_temptimer, svc_age_temp_xprts, + (unsigned long)serv); + mod_timer(&serv->sv_temptimer, + jiffies + svc_conn_age_period * HZ); + } + spin_unlock_bh(&serv->sv_lock); + svc_xprt_received(newxpt); +} + +static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) +{ + struct svc_serv *serv = rqstp->rq_server; + int len = 0; - len = 0; if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { dprintk("svc_recv: found XPT_CLOSE\n"); svc_delete_xprt(xprt); /* Leave XPT_BUSY set on the dead xprt: */ - goto out; + return 0; } if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { struct svc_xprt *newxpt; + /* + * We know this module_get will succeed because the + * listener holds a reference too + */ + __module_get(xprt->xpt_class->xcl_owner); + svc_check_conn_limits(xprt->xpt_server); newxpt = xprt->xpt_ops->xpo_accept(xprt); - if (newxpt) { - /* - * We know this module_get will succeed because the - * listener holds a reference too - */ - __module_get(newxpt->xpt_class->xcl_owner); - svc_check_conn_limits(xprt->xpt_server); - spin_lock_bh(&serv->sv_lock); - set_bit(XPT_TEMP, &newxpt->xpt_flags); - list_add(&newxpt->xpt_list, &serv->sv_tempsocks); - serv->sv_tmpcnt++; - if (serv->sv_temptimer.function == NULL) { - /* setup timer to age temp transports */ - setup_timer(&serv->sv_temptimer, - svc_age_temp_xprts, - (unsigned long)serv); - mod_timer(&serv->sv_temptimer, - jiffies + svc_conn_age_period * HZ); - } - spin_unlock_bh(&serv->sv_lock); - svc_xprt_received(newxpt); - } + if (newxpt) + svc_add_new_temp_xprt(serv, newxpt); } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) { + /* XPT_DATA|XPT_DEFERRED case: */ dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", - rqstp, pool->sp_id, xprt, + rqstp, rqstp->rq_pool->sp_id, xprt, atomic_read(&xprt->xpt_ref.refcount)); rqstp->rq_deferred = svc_deferred_dequeue(xprt); if (rqstp->rq_deferred) @@ -736,10 +732,51 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) rqstp->rq_reserved = serv->sv_max_mesg; atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); } + /* clear XPT_BUSY: */ svc_xprt_received(xprt); + return len; +} + +/* + * Receive the next request on any transport. This code is carefully + * organised not to touch any cachelines in the shared svc_serv + * structure, only cachelines in the local svc_pool. + */ +int svc_recv(struct svc_rqst *rqstp, long timeout) +{ + struct svc_xprt *xprt = NULL; + struct svc_serv *serv = rqstp->rq_server; + int len, err; + + dprintk("svc: server %p waiting for data (to = %ld)\n", + rqstp, timeout); + + if (rqstp->rq_xprt) + printk(KERN_ERR + "svc_recv: service %p, transport not NULL!\n", + rqstp); + if (waitqueue_active(&rqstp->rq_wait)) + printk(KERN_ERR + "svc_recv: service %p, wait queue active!\n", + rqstp); + + err = svc_alloc_arg(rqstp); + if (err) + return err; + + try_to_freeze(); + cond_resched(); + if (signalled() || kthread_should_stop()) + return -EINTR; + + xprt = svc_get_next_xprt(rqstp, timeout); + if (IS_ERR(xprt)) + return PTR_ERR(xprt); + + len = svc_handle_xprt(rqstp, xprt); /* No data, incomplete (TCP) read, or accept() */ - if (len == 0 || len == -EAGAIN) + if (len <= 0) goto out; clear_bit(XPT_OLD, &xprt->xpt_flags); @@ -917,16 +954,18 @@ void svc_close_xprt(struct svc_xprt *xprt) } EXPORT_SYMBOL_GPL(svc_close_xprt); -static void svc_close_list(struct list_head *xprt_list, struct net *net) +static void svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) { struct svc_xprt *xprt; + spin_lock(&serv->sv_lock); list_for_each_entry(xprt, xprt_list, xpt_list) { if (xprt->xpt_net != net) continue; set_bit(XPT_CLOSE, &xprt->xpt_flags); set_bit(XPT_BUSY, &xprt->xpt_flags); } + spin_unlock(&serv->sv_lock); } static void svc_clear_pools(struct svc_serv *serv, struct net *net) @@ -949,24 +988,28 @@ static void svc_clear_pools(struct svc_serv *serv, struct net *net) } } -static void svc_clear_list(struct list_head *xprt_list, struct net *net) +static void svc_clear_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) { struct svc_xprt *xprt; struct svc_xprt *tmp; + LIST_HEAD(victims); + spin_lock(&serv->sv_lock); list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { if (xprt->xpt_net != net) continue; - svc_delete_xprt(xprt); + list_move(&xprt->xpt_list, &victims); } - list_for_each_entry(xprt, xprt_list, xpt_list) - BUG_ON(xprt->xpt_net == net); + spin_unlock(&serv->sv_lock); + + list_for_each_entry_safe(xprt, tmp, &victims, xpt_list) + svc_delete_xprt(xprt); } void svc_close_net(struct svc_serv *serv, struct net *net) { - svc_close_list(&serv->sv_tempsocks, net); - svc_close_list(&serv->sv_permsocks, net); + svc_close_list(serv, &serv->sv_tempsocks, net); + svc_close_list(serv, &serv->sv_permsocks, net); svc_clear_pools(serv, net); /* @@ -974,8 +1017,8 @@ void svc_close_net(struct svc_serv *serv, struct net *net) * svc_xprt_enqueue will not add new entries without taking the * sp_lock and checking XPT_BUSY. */ - svc_clear_list(&serv->sv_tempsocks, net); - svc_clear_list(&serv->sv_permsocks, net); + svc_clear_list(serv, &serv->sv_tempsocks, net); + svc_clear_list(serv, &serv->sv_permsocks, net); } /* diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 998aa8c1807c..03827cef1fa7 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -59,7 +59,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, - int *errp, int flags); + int flags); static void svc_udp_data_ready(struct sock *, int); static int svc_udp_recvfrom(struct svc_rqst *); static int svc_udp_sendto(struct svc_rqst *); @@ -305,57 +305,6 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) return len; } -/** - * svc_sock_names - construct a list of listener names in a string - * @serv: pointer to RPC service - * @buf: pointer to a buffer to fill in with socket names - * @buflen: size of the buffer to be filled - * @toclose: pointer to '\0'-terminated C string containing the name - * of a listener to be closed - * - * Fills in @buf with a '\n'-separated list of names of listener - * sockets. If @toclose is not NULL, the socket named by @toclose - * is closed, and is not included in the output list. - * - * Returns positive length of the socket name string, or a negative - * errno value on error. - */ -int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen, - const char *toclose) -{ - struct svc_sock *svsk, *closesk = NULL; - int len = 0; - - if (!serv) - return 0; - - spin_lock_bh(&serv->sv_lock); - list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { - int onelen = svc_one_sock_name(svsk, buf + len, buflen - len); - if (onelen < 0) { - len = onelen; - break; - } - if (toclose && strcmp(toclose, buf + len) == 0) { - closesk = svsk; - svc_xprt_get(&closesk->sk_xprt); - } else - len += onelen; - } - spin_unlock_bh(&serv->sv_lock); - - if (closesk) { - /* Should unregister with portmap, but you cannot - * unregister just one protocol... - */ - svc_close_xprt(&closesk->sk_xprt); - svc_xprt_put(&closesk->sk_xprt); - } else if (toclose) - return -ENOENT; - return len; -} -EXPORT_SYMBOL_GPL(svc_sock_names); - /* * Check input queue length */ @@ -598,11 +547,9 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) dprintk("svc: recvfrom returned error %d\n", -err); set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); } - return -EAGAIN; + return 0; } len = svc_addr_len(svc_addr(rqstp)); - if (len == 0) - return -EAFNOSUPPORT; rqstp->rq_addrlen = len; if (skb->tstamp.tv64 == 0) { skb->tstamp = ktime_get_real(); @@ -620,10 +567,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) if (!svc_udp_get_dest_address(rqstp, cmh)) { net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram\n", cmh->cmsg_level, cmh->cmsg_type); -out_free: - trace_kfree_skb(skb, svc_udp_recvfrom); - skb_free_datagram_locked(svsk->sk_sk, skb); - return 0; + goto out_free; } rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp)); @@ -662,6 +606,10 @@ out_free: serv->sv_stats->netudpcnt++; return len; +out_free: + trace_kfree_skb(skb, svc_udp_recvfrom); + skb_free_datagram_locked(svsk->sk_sk, skb); + return 0; } static int @@ -900,8 +848,9 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt) */ newsock->sk->sk_sndtimeo = HZ*30; - if (!(newsvsk = svc_setup_socket(serv, newsock, &err, - (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY)))) + newsvsk = svc_setup_socket(serv, newsock, + (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY)); + if (IS_ERR(newsvsk)) goto failed; svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen); err = kernel_getsockname(newsock, sin, &slen); @@ -1174,13 +1123,13 @@ error: if (len != -EAGAIN) goto err_other; dprintk("RPC: TCP recvfrom got EAGAIN\n"); - return -EAGAIN; + return 0; err_other: printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", svsk->sk_xprt.xpt_server->sv_name, -len); set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); err_noclose: - return -EAGAIN; /* record not complete */ + return 0; /* record not complete */ } /* @@ -1383,29 +1332,29 @@ EXPORT_SYMBOL_GPL(svc_sock_update_bufs); */ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, struct socket *sock, - int *errp, int flags) + int flags) { struct svc_sock *svsk; struct sock *inet; int pmap_register = !(flags & SVC_SOCK_ANONYMOUS); + int err = 0; dprintk("svc: svc_setup_socket %p\n", sock); - if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) { - *errp = -ENOMEM; - return NULL; - } + svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); + if (!svsk) + return ERR_PTR(-ENOMEM); inet = sock->sk; /* Register socket with portmapper */ - if (*errp >= 0 && pmap_register) - *errp = svc_register(serv, sock_net(sock->sk), inet->sk_family, + if (pmap_register) + err = svc_register(serv, sock_net(sock->sk), inet->sk_family, inet->sk_protocol, ntohs(inet_sk(inet)->inet_sport)); - if (*errp < 0) { + if (err < 0) { kfree(svsk); - return NULL; + return ERR_PTR(err); } inet->sk_user_data = svsk; @@ -1450,42 +1399,38 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, int err = 0; struct socket *so = sockfd_lookup(fd, &err); struct svc_sock *svsk = NULL; + struct sockaddr_storage addr; + struct sockaddr *sin = (struct sockaddr *)&addr; + int salen; if (!so) return err; + err = -EAFNOSUPPORT; if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6)) - err = -EAFNOSUPPORT; - else if (so->sk->sk_protocol != IPPROTO_TCP && + goto out; + err = -EPROTONOSUPPORT; + if (so->sk->sk_protocol != IPPROTO_TCP && so->sk->sk_protocol != IPPROTO_UDP) - err = -EPROTONOSUPPORT; - else if (so->state > SS_UNCONNECTED) - err = -EISCONN; - else { - if (!try_module_get(THIS_MODULE)) - err = -ENOENT; - else - svsk = svc_setup_socket(serv, so, &err, - SVC_SOCK_DEFAULTS); - if (svsk) { - struct sockaddr_storage addr; - struct sockaddr *sin = (struct sockaddr *)&addr; - int salen; - if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0) - svc_xprt_set_local(&svsk->sk_xprt, sin, salen); - clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags); - spin_lock_bh(&serv->sv_lock); - list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks); - spin_unlock_bh(&serv->sv_lock); - svc_xprt_received(&svsk->sk_xprt); - err = 0; - } else - module_put(THIS_MODULE); - } - if (err) { - sockfd_put(so); - return err; + goto out; + err = -EISCONN; + if (so->state > SS_UNCONNECTED) + goto out; + err = -ENOENT; + if (!try_module_get(THIS_MODULE)) + goto out; + svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS); + if (IS_ERR(svsk)) { + module_put(THIS_MODULE); + err = PTR_ERR(svsk); + goto out; } + if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0) + svc_xprt_set_local(&svsk->sk_xprt, sin, salen); + svc_add_new_perm_xprt(serv, &svsk->sk_xprt); return svc_one_sock_name(svsk, name_return, len); +out: + sockfd_put(so); + return err; } EXPORT_SYMBOL_GPL(svc_addsock); @@ -1563,11 +1508,13 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv, goto bummer; } - if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) { - svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen); - return (struct svc_xprt *)svsk; + svsk = svc_setup_socket(serv, sock, flags); + if (IS_ERR(svsk)) { + error = PTR_ERR(svsk); + goto bummer; } - + svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen); + return (struct svc_xprt *)svsk; bummer: dprintk("svc: svc_create_socket error = %d\n", -error); sock_release(sock); diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 73b428bef598..62e4f9bcc387 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -578,10 +578,6 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird) list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q); spin_unlock_bh(&listen_xprt->sc_lock); - /* - * Can't use svc_xprt_received here because we are not on a - * rqstp thread - */ set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags); svc_xprt_enqueue(&listen_xprt->sc_xprt); } diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index efa5d940e632..3d13d3a3edfe 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -9,7 +9,7 @@ include scripts/Kbuild.include # -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) PHONY += $(modules) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 08dce14f2dc8..a1cb0222ebe6 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -60,7 +60,7 @@ kernelsymfile := $(objtree)/Module.symvers modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers # Step 1), find all modules listed in $(MODVERDIR)/ -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) # Stop after building .o files if NOFINAL is set. Makes compile tests quicker diff --git a/scripts/coccicheck b/scripts/coccicheck index 823e972149e5..1a49d1c7ecfe 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -95,6 +95,9 @@ coccinelle () { $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \ $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \ $SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1 + elif [ "$MODE" = "rep+ctxt" ] ; then + $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff && \ + $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 else $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 fi diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci index cbfd08c7d8c7..15f076fdecbe 100644 --- a/scripts/coccinelle/api/ptr_ret.cocci +++ b/scripts/coccinelle/api/ptr_ret.cocci @@ -30,6 +30,13 @@ expression ptr; - if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; + return PTR_RET(ptr); +@depends on patch@ +expression ptr; +@@ + +- (IS_ERR(ptr) ? PTR_ERR(ptr) : 0) ++ PTR_RET(ptr) + @r1 depends on !patch@ expression ptr; position p1; @@ -44,6 +51,13 @@ position p2; * if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; +@r3 depends on !patch@ +expression ptr; +position p3; +@@ + +* IS_ERR@p3(ptr) ? PTR_ERR(ptr) : 0 + @script:python depends on org@ p << r1.p1; @@ @@ -57,6 +71,12 @@ p << r2.p2; coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") +@script:python depends on org@ +p << r3.p3; +@@ + +coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") + @script:python depends on report@ p << r1.p1; @@ @@ -68,3 +88,9 @@ p << r2.p2; @@ coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") + +@script:python depends on report@ +p << r3.p3; +@@ + +coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci new file mode 100644 index 000000000000..e8dd8a6b28a2 --- /dev/null +++ b/scripts/coccinelle/tests/odd_ptr_err.cocci @@ -0,0 +1,65 @@ +/// PTR_ERR should access the value just tested by IS_ERR +//# There can be false positives in the patch case, where it is the call +//# IS_ERR that is wrong. +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on patch@ +expression e,e1; +@@ + +( +if (IS_ERR(e)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e)) + { ... + PTR_ERR( +- e1 ++ e + ) + ... } +) + +@r depends on !patch@ +expression e,e1; +position p1,p2; +@@ + +( +if (IS_ERR(e)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } +| +*if (IS_ERR@p1(e)) + { ... +* PTR_ERR@p2(e1) + ... } +) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("inconsistent IS_ERR and PTR_ERR",p1) +cocci.print_secs("PTR_ERR",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "inconsistent IS_ERR and PTR_ERR, PTR_ERR on line %s" % (p2[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 77d53999ffb9..3091794e9354 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -76,11 +76,17 @@ PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf $< --$@ $(Kconfig) -PHONY += listnewconfig oldnoconfig savedefconfig defconfig +PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig -listnewconfig oldnoconfig: $(obj)/conf +listnewconfig olddefconfig: $(obj)/conf $< --$@ $(Kconfig) +# oldnoconfig is an alias of olddefconfig, because people already are dependent +# on its behavior(sets new symbols to their default value but not 'n') with the +# counter-intuitive name. +oldnoconfig: $(obj)/conf + $< --olddefconfig $(Kconfig) + savedefconfig: $(obj)/conf $< --$@=defconfig $(Kconfig) @@ -114,7 +120,7 @@ help: @echo ' alldefconfig - New config with all symbols set to default' @echo ' randconfig - New config with random answer to all options' @echo ' listnewconfig - List new options' - @echo ' oldnoconfig - Same as silentoldconfig but sets new symbols to their default value' + @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' # lxdialog stuff check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 0dc4a2c779b1..4da3b4adfad2 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -32,7 +32,7 @@ enum input_mode { defconfig, savedefconfig, listnewconfig, - oldnoconfig, + olddefconfig, } input_mode = oldaskconfig; static int indent = 1; @@ -365,7 +365,7 @@ static void conf(struct menu *menu) case P_MENU: if ((input_mode == silentoldconfig || input_mode == listnewconfig || - input_mode == oldnoconfig) && + input_mode == olddefconfig) && rootEntry != menu) { check_conf(menu); return; @@ -429,7 +429,7 @@ static void check_conf(struct menu *menu) if (sym->name && !sym_is_choice_value(sym)) { printf("%s%s\n", CONFIG_, sym->name); } - } else if (input_mode != oldnoconfig) { + } else if (input_mode != olddefconfig) { if (!conf_cnt++) printf(_("*\n* Restart config...\n*\n")); rootEntry = menu_get_parent_menu(menu); @@ -454,7 +454,13 @@ static struct option long_opts[] = { {"alldefconfig", no_argument, NULL, alldefconfig}, {"randconfig", no_argument, NULL, randconfig}, {"listnewconfig", no_argument, NULL, listnewconfig}, - {"oldnoconfig", no_argument, NULL, oldnoconfig}, + {"olddefconfig", no_argument, NULL, olddefconfig}, + /* + * oldnoconfig is an alias of olddefconfig, because people already + * are dependent on its behavior(sets new symbols to their default + * value but not 'n') with the counter-intuitive name. + */ + {"oldnoconfig", no_argument, NULL, olddefconfig}, {NULL, 0, NULL, 0} }; @@ -467,7 +473,8 @@ static void conf_usage(const char *progname) printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); printf(" --oldconfig Update a configuration using a provided .config as base\n"); printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); - printf(" --oldnoconfig Same as silentoldconfig but set new symbols to no\n"); + printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); + printf(" --oldnoconfig An alias of olddefconfig\n"); printf(" --defconfig <file> New config with default defined in <file>\n"); printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); printf(" --allnoconfig New config where all options are answered with no\n"); @@ -520,7 +527,7 @@ int main(int ac, char **av) case allmodconfig: case alldefconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: break; case '?': conf_usage(progname); @@ -565,7 +572,7 @@ int main(int ac, char **av) case oldaskconfig: case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: conf_read(NULL); break; case allnoconfig: @@ -645,7 +652,7 @@ int main(int ac, char **av) /* fall through */ case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: case silentoldconfig: /* Update until a loop caused no more changes */ do { @@ -653,7 +660,7 @@ int main(int ac, char **av) check_conf(&rootmenu); } while (conf_cnt && (input_mode != listnewconfig && - input_mode != oldnoconfig)); + input_mode != olddefconfig)); break; } diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index d4ecce8bc3a6..bd2e09895553 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -12,6 +12,7 @@ extern "C" { #include <assert.h> #include <stdio.h> +#include <sys/queue.h> #ifndef __cplusplus #include <stdbool.h> #endif @@ -173,6 +174,16 @@ struct menu { #define MENU_CHANGED 0x0001 #define MENU_ROOT 0x0002 +struct jump_key { + CIRCLEQ_ENTRY(jump_key) entries; + size_t offset; + struct menu *target; + int index; +}; +CIRCLEQ_HEAD(jk_head, jump_key); + +#define JUMP_NB 9 + extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 47fe9c340f9a..1d1c08537f1e 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -21,8 +21,10 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu)); -P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); -P(get_relations_str, struct gstr, (struct symbol **sym_arr)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct jk_head + *head)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct jk_head + *head)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); /* symbol.c */ diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index b5211fce0d94..ee17a5264d5b 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -144,6 +144,7 @@ struct dialog_info { */ extern struct dialog_info dlg; extern char dialog_input_result[]; +extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ /* * Function prototypes @@ -209,7 +210,13 @@ int first_alpha(const char *string, const char *exempt); int dialog_yesno(const char *title, const char *prompt, int height, int width); int dialog_msgbox(const char *title, const char *prompt, int height, int width, int pause); -int dialog_textbox(const char *title, const char *file, int height, int width); + + +typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void + *_data); +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data); int dialog_menu(const char *title, const char *prompt, const void *selected, int *s_scroll); int dialog_checklist(const char *title, const char *prompt, int height, diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 4e5de60a0c0d..a48bb93e0907 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -22,23 +22,25 @@ #include "dialog.h" static void back_lines(int n); -static void print_page(WINDOW * win, int height, int width); -static void print_line(WINDOW * win, int row, int width); +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data); +static void print_line(WINDOW *win, int row, int width); static char *get_line(void); static void print_position(WINDOW * win); static int hscroll; static int begin_reached, end_reached, page_length; -static const char *buf; -static const char *page; +static char *buf; +static char *page; /* * refresh window content */ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, - int cur_y, int cur_x) + int cur_y, int cur_x, update_text_fn update_text, + void *data) { - print_page(box, boxh, boxw); + print_page(box, boxh, boxw, update_text, data); print_position(dialog); wmove(dialog, cur_y, cur_x); /* Restore cursor position */ wrefresh(dialog); @@ -47,14 +49,18 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, /* * Display text from a file in a dialog box. + * + * keys is a null-terminated array + * update_text() may not add or remove any '\n' or '\0' in tbuf */ -int dialog_textbox(const char *title, const char *tbuf, - int initial_height, int initial_width) +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data) { int i, x, y, cur_x, cur_y, key = 0; int height, width, boxh, boxw; - int passed_end; WINDOW *dialog, *box; + bool done = false; begin_reached = 1; end_reached = 0; @@ -63,6 +69,15 @@ int dialog_textbox(const char *title, const char *tbuf, buf = tbuf; page = buf; /* page is pointer to start of page to be displayed */ + if (_vscroll && *_vscroll) { + begin_reached = 0; + + for (i = 0; i < *_vscroll; i++) + get_line(); + } + if (_hscroll) + hscroll = *_hscroll; + do_resize: getmaxyx(stdscr, height, width); if (height < 8 || width < 8) @@ -120,9 +135,10 @@ do_resize: /* Print first page of text */ attr_clear(box, boxh, boxw, dlg.dialog.atr); - refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, + data); - while ((key != KEY_ESC) && (key != '\n')) { + while (!done) { key = wgetch(dialog); switch (key) { case 'E': /* Exit */ @@ -130,16 +146,17 @@ do_resize: case 'X': case 'x': case 'q': - delwin(box); - delwin(dialog); - return 0; + case '\n': + done = true; + break; case 'g': /* First page */ case KEY_HOME: if (!begin_reached) { begin_reached = 1; page = buf; refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + cur_y, cur_x, update_text, + data); } break; case 'G': /* Last page */ @@ -149,45 +166,18 @@ do_resize: /* point to last char in buf */ page = buf + strlen(buf); back_lines(boxh); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'K': /* Previous line */ case 'k': case KEY_UP: - if (!begin_reached) { - back_lines(page_length + 1); - - /* We don't call print_page() here but use - * scrolling to ensure faster screen update. - * However, 'end_reached' and 'page_length' - * should still be updated, and 'page' should - * point to start of next page. This is done - * by calling get_line() in the following - * 'for' loop. */ - scrollok(box, TRUE); - wscrl(box, -1); /* Scroll box region down one line */ - scrollok(box, FALSE); - page_length = 0; - passed_end = 0; - for (i = 0; i < boxh; i++) { - if (!i) { - /* print first line of page */ - print_line(box, 0, boxw); - wnoutrefresh(box); - } else - /* Called to update 'end_reached' and 'page' */ - get_line(); - if (!passed_end) - page_length++; - if (end_reached && !passed_end) - passed_end = 1; - } + if (begin_reached) + break; - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); - } + back_lines(page_length + 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'B': /* Previous page */ case 'b': @@ -196,23 +186,18 @@ do_resize: if (begin_reached) break; back_lines(page_length + boxh); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'J': /* Next line */ case 'j': case KEY_DOWN: - if (!end_reached) { - begin_reached = 0; - scrollok(box, TRUE); - scroll(box); /* Scroll box region up one line */ - scrollok(box, FALSE); - print_line(box, boxh - 1, boxw); - wnoutrefresh(box); - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); - } + if (end_reached) + break; + + back_lines(page_length - 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case KEY_NPAGE: /* Next page */ case ' ': @@ -221,8 +206,8 @@ do_resize: break; begin_reached = 0; - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case '0': /* Beginning of line */ case 'H': /* Scroll left */ @@ -237,8 +222,8 @@ do_resize: hscroll--; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'L': /* Scroll right */ case 'l': @@ -248,11 +233,12 @@ do_resize: hscroll++; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case KEY_ESC: - key = on_key_esc(dialog); + if (on_key_esc(dialog) == KEY_ESC) + done = true; break; case KEY_RESIZE: back_lines(height); @@ -260,11 +246,31 @@ do_resize: delwin(dialog); on_key_resize(); goto do_resize; + default: + for (i = 0; keys[i]; i++) { + if (key == keys[i]) { + done = true; + break; + } + } } } delwin(box); delwin(dialog); - return key; /* ESC pressed */ + if (_vscroll) { + const char *s; + + s = buf; + *_vscroll = 0; + back_lines(page_length); + while (s < page && (s = strchr(s, '\n'))) { + (*_vscroll)++; + s++; + } + } + if (_hscroll) + *_hscroll = hscroll; + return key; } /* @@ -301,12 +307,23 @@ static void back_lines(int n) } /* - * Print a new page of text. Called by dialog_textbox(). + * Print a new page of text. */ -static void print_page(WINDOW * win, int height, int width) +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data) { int i, passed_end = 0; + if (update_text) { + char *end; + + for (i = 0; i < height; i++) + get_line(); + end = page; + back_lines(height); + update_text(buf, page - buf, end - buf, data); + } + page_length = 0; for (i = 0; i < height; i++) { print_line(win, i, width); @@ -319,7 +336,7 @@ static void print_page(WINDOW * win, int height, int width) } /* - * Print a new line of text. Called by dialog_textbox() and print_page(). + * Print a new line of text. */ static void print_line(WINDOW * win, int row, int width) { @@ -357,10 +374,8 @@ static char *get_line(void) end_reached = 0; while (*page != '\n') { if (*page == '\0') { - if (!end_reached) { - end_reached = 1; - break; - } + end_reached = 1; + break; } else if (i < MAX_LEN) line[i++] = *(page++); else { @@ -373,7 +388,7 @@ static char *get_line(void) if (i <= MAX_LEN) line[i] = '\0'; if (!end_reached) - page++; /* move pass '\n' */ + page++; /* move past '\n' */ return line; } diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index f2375ad7ebc9..109d53117d22 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -23,6 +23,9 @@ #include "dialog.h" +/* Needed in signal handler in mconf.c */ +int saved_x, saved_y; + struct dialog_info dlg; static void set_mono_theme(void) @@ -273,6 +276,10 @@ int init_dialog(const char *backtitle) int height, width; initscr(); /* Init curses */ + + /* Get current cursor position for signal handler in mconf.c */ + getyx(stdscr, saved_y, saved_x); + getmaxyx(stdscr, height, width); if (height < 19 || width < 80) { endwin(); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index f584a281bb4c..48f67448af7b 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -236,16 +236,19 @@ search_help[] = N_( "Result:\n" "-----------------------------------------------------------------\n" "Symbol: FOO [=m]\n" + "Type : tristate\n" "Prompt: Foo bus is used to drive the bar HW\n" - "Defined at drivers/pci/Kconfig:47\n" - "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" - "Location:\n" - " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" - " -> PCI support (PCI [=y])\n" - " -> PCI access mode (<choice> [=y])\n" - "Selects: LIBCRC32\n" - "Selected by: BAR\n" + " Defined at drivers/pci/Kconfig:47\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" + " -> PCI support (PCI [=y])\n" + "(1) -> PCI access mode (<choice> [=y])\n" + " Selects: LIBCRC32\n" + " Selected by: BAR\n" "-----------------------------------------------------------------\n" + "o The line 'Type:' shows the type of the configuration option for\n" + " this symbol (boolean, tristate, string, ...)\n" "o The line 'Prompt:' shows the text used in the menu structure for\n" " this symbol\n" "o The 'Defined at' line tell at what file / line number the symbol\n" @@ -254,8 +257,12 @@ search_help[] = N_( " this symbol to be visible in the menu (selectable)\n" "o The 'Location:' lines tell where in the menu structure this symbol\n" " is located\n" - " A location followed by a [=y] indicate that this is a selectable\n" - " menu item - and current value is displayed inside brackets.\n" + " A location followed by a [=y] indicates that this is a\n" + " selectable menu item - and the current value is displayed inside\n" + " brackets.\n" + " Press the key in the (#) prefix to jump directly to that\n" + " location. You will be returned to the current search results\n" + " after exiting this new menu.\n" "o The 'Selects:' line tell what symbol will be automatically\n" " selected if this symbol is selected (y or m)\n" "o The 'Selected by' line tell what symbol has selected this symbol\n" @@ -273,13 +280,15 @@ static struct menu *current_menu; static int child_count; static int single_menu_mode; static int show_all_options; -static int saved_x, saved_y; -static void conf(struct menu *menu); +static void conf(struct menu *menu, struct menu *active_menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); static void conf_load(void); static void conf_save(void); +static int show_textbox_ext(const char *title, char *text, int r, int c, + int *keys, int *vscroll, int *hscroll, + update_text_fn update_text, void *data); static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); @@ -302,12 +311,47 @@ static void set_config_filename(const char *config_filename) } +struct search_data { + struct jk_head *head; + struct menu **targets; + int *keys; +}; + +static void update_text(char *buf, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int k = 0; + + CIRCLEQ_FOREACH(pos, data->head, entries) { + if (pos->offset >= start && pos->offset < end) { + char header[4]; + + if (k < JUMP_NB) { + int key = '0' + (pos->index % JUMP_NB) + 1; + + sprintf(header, "(%c)", key); + data->keys[k] = key; + data->targets[k] = pos->target; + k++; + } else { + sprintf(header, " "); + } + + memcpy(buf + pos->offset, header, sizeof(header) - 1); + } + } + data->keys[k] = 0; +} + static void search_conf(void) { struct symbol **sym_arr; struct gstr res; char *dialog_input; - int dres; + int dres, vscroll = 0, hscroll = 0; + bool again; + again: dialog_clear(); dres = dialog_inputbox(_("Search Configuration Parameter"), @@ -330,10 +374,30 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr); + do { + struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head); + struct menu *targets[JUMP_NB]; + int keys[JUMP_NB + 1], i; + struct search_data data = { + .head = &head, + .targets = targets, + .keys = keys, + }; + + res = get_relations_str(sym_arr, &head); + dres = show_textbox_ext(_("Search Results"), (char *) + str_get(&res), 0, 0, keys, &vscroll, + &hscroll, &update_text, (void *) + &data); + again = false; + for (i = 0; i < JUMP_NB && keys[i]; i++) + if (dres == keys[i]) { + conf(targets[i]->parent, targets[i]); + again = true; + } + str_free(&res); + } while (again); free(sym_arr); - show_textbox(_("Search Results"), str_get(&res), 0, 0); - str_free(&res); } static void build_conf(struct menu *menu) @@ -514,12 +578,11 @@ conf_childs: indent -= doint; } -static void conf(struct menu *menu) +static void conf(struct menu *menu, struct menu *active_menu) { struct menu *submenu; const char *prompt = menu_get_prompt(menu); struct symbol *sym; - struct menu *active_menu = NULL; int res; int s_scroll = 0; @@ -562,13 +625,13 @@ static void conf(struct menu *menu) if (single_menu_mode) submenu->data = (void *) (long) !submenu->data; else - conf(submenu); + conf(submenu, NULL); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); else if (submenu->prompt->type == P_MENU) - conf(submenu); + conf(submenu, NULL); break; case 's': conf_string(submenu); @@ -607,7 +670,7 @@ static void conf(struct menu *menu) if (item_is_tag('t')) sym_toggle_tristate_value(sym); else if (item_is_tag('m')) - conf(submenu); + conf(submenu, NULL); break; case 7: search_conf(); @@ -619,10 +682,19 @@ static void conf(struct menu *menu) } } -static void show_textbox(const char *title, const char *text, int r, int c) +static int show_textbox_ext(const char *title, char *text, int r, int c, int + *keys, int *vscroll, int *hscroll, update_text_fn + update_text, void *data) { dialog_clear(); - dialog_textbox(title, text, r, c); + return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, + update_text, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, + NULL, NULL); } static void show_helptext(const char *title, const char *text) @@ -862,9 +934,6 @@ int main(int ac, char **av) single_menu_mode = 1; } - initscr(); - - getyx(stdscr, saved_y, saved_x); if (init_dialog(NULL)) { fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); @@ -873,7 +942,7 @@ int main(int ac, char **av) set_config_filename(conf_get_configname()); do { - conf(&rootmenu); + conf(&rootmenu, NULL); res = handle_exit(); } while (res == KEY_ESC); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 8c2a97e60faf..a3cade659f89 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -507,10 +507,12 @@ const char *menu_get_help(struct menu *menu) return ""; } -static void get_prompt_str(struct gstr *r, struct property *prop) +static void get_prompt_str(struct gstr *r, struct property *prop, + struct jk_head *head) { int i, j; - struct menu *submenu[8], *menu; + struct menu *submenu[8], *menu, *location = NULL; + struct jump_key *jump; str_printf(r, _("Prompt: %s\n"), _(prop->text)); str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, @@ -521,13 +523,43 @@ static void get_prompt_str(struct gstr *r, struct property *prop) str_append(r, "\n"); } menu = prop->menu->parent; - for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { + bool accessible = menu_is_visible(menu); + submenu[i++] = menu; + if (location == NULL && accessible) + location = menu; + } + if (head && location) { + jump = malloc(sizeof(struct jump_key)); + + if (menu_is_visible(prop->menu)) { + /* + * There is not enough room to put the hint at the + * beginning of the "Prompt" line. Put the hint on the + * last "Location" line even when it would belong on + * the former. + */ + jump->target = prop->menu; + } else + jump->target = location; + + if (CIRCLEQ_EMPTY(head)) + jump->index = 0; + else + jump->index = CIRCLEQ_LAST(head)->index + 1; + + CIRCLEQ_INSERT_TAIL(head, jump, entries); + } + if (i > 0) { str_printf(r, _(" Location:\n")); for (j = 4; --i >= 0; j += 2) { menu = submenu[i]; - str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); + if (head && location && menu == location) + jump->offset = r->len - 1; + str_printf(r, "%*c-> %s", j, ' ', + _(menu_get_prompt(menu))); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? menu->sym->name : _("<choice>"), @@ -538,7 +570,10 @@ static void get_prompt_str(struct gstr *r, struct property *prop) } } -void get_symbol_str(struct gstr *r, struct symbol *sym) +/* + * head is optional and may be NULL + */ +void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head) { bool hit; struct property *prop; @@ -557,7 +592,7 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) } } for_all_prompts(sym, prop) - get_prompt_str(r, prop); + get_prompt_str(r, prop, head); hit = false; for_all_properties(sym, prop, P_SELECT) { if (!hit) { @@ -577,14 +612,14 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) str_append(r, "\n\n"); } -struct gstr get_relations_str(struct symbol **sym_arr) +struct gstr get_relations_str(struct symbol **sym_arr, struct jk_head *head) { struct symbol *sym; struct gstr res = str_new(); int i; for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym); + get_symbol_str(&res, sym, head); if (!i) str_append(&res, _("No matches found.\n")); return res; @@ -603,5 +638,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) } str_printf(help, "%s\n", _(help_text)); if (sym) - get_symbol_str(help, sym); + get_symbol_str(help, sym, NULL); } diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 1704a8562a5d..87d4b15da951 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -721,7 +721,7 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr); + res = get_relations_str(sym_arr, NULL); free(sym_arr); show_scroll_win(main_window, _("Search Results"), str_get(&res)); diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 01e8a8e22602..46e7aff80d1a 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -6,6 +6,7 @@ use strict; ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## ## Copyright (C) 2005-2012 Randy Dunlap ## +## Copyright (C) 2012 Dan Luedtke ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -35,6 +36,8 @@ use strict; # Small fixes (like spaces vs. \s in regex) # -- Tim Jansen <tim@tjansen.de> +# 25/07/2012 - Added support for HTML5 +# -- Dan Luedtke <mail@danrl.de> # # This will read a 'c' file and scan for embedded comments in the @@ -44,12 +47,16 @@ use strict; # Note: This only supports 'c'. # usage: -# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ] -# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile +# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ] +# [ -no-doc-sections ] +# [ -function funcname [ -function funcname ...] ] +# c file(s)s > outputfile # or -# [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile +# [ -nofunction funcname [ -function funcname ...] ] +# c file(s)s > outputfile # -# Set output format using one of -docbook -html -text or -man. Default is man. +# Set output format using one of -docbook -html -html5 -text or -man. +# Default is man. # The -list format is for internal use by docproc. # # -no-doc-sections @@ -182,6 +189,14 @@ my $local_lt = "\\\\\\\\lt:"; my $local_gt = "\\\\\\\\gt:"; my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" +# html version 5 +my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>", + $type_func, "<span class=\"func\">\$1</span>", + $type_struct_xml, "<span class=\"struct\">\$1</span>", + $type_env, "<span class=\"env\">\$1</span>", + $type_param, "<span class=\"param\">\$1</span>" ); +my $blankline_html5 = $local_lt . "br /" . $local_gt; + # XML, docbook format my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>", $type_constant, "<constant>\$1</constant>", @@ -311,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "html"; %highlights = %highlights_html; $blankline = $blankline_html; + } elsif ($cmd eq "-html5") { + $output_mode = "html5"; + %highlights = %highlights_html5; + $blankline = $blankline_html5; } elsif ($cmd eq "-man") { $output_mode = "man"; %highlights = %highlights_man; @@ -353,10 +372,11 @@ while ($ARGV[0] =~ m/^-(.*)/) { # continue execution near EOF; sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; + print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n"; print " [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; + print " [ -v ]\n"; print " c source file(s) > outputfile\n"; print " -v : verbose output, more warnings & other info listed\n"; exit 1; @@ -450,7 +470,8 @@ sub output_highlight { # confess "output_highlight got called with no args?\n"; # } - if ($output_mode eq "html" || $output_mode eq "xml") { + if ($output_mode eq "html" || $output_mode eq "html5" || + $output_mode eq "xml") { $contents = local_unescape($contents); # convert data read & converted thru xml_escape() into &xyz; format: $contents =~ s/\\\\\\/\&/g; @@ -460,6 +481,11 @@ sub output_highlight { die $@ if $@; # print STDERR "contents af:$contents\n"; +# strip whitespaces when generating html5 + if ($output_mode eq "html5") { + $contents =~ s/^\s+//; + $contents =~ s/\s+$//; + } foreach $line (split "\n", $contents) { if (! $output_preformatted) { $line =~ s/^\s*//; @@ -480,7 +506,7 @@ sub output_highlight { } } -#output sections in html +# output sections in html sub output_section_html(%) { my %args = %{$_[0]}; my $section; @@ -640,6 +666,239 @@ sub output_blockhead_html(%) { print "<hr>\n"; } +# output sections in html5 +sub output_section_html5(%) { + my %args = %{$_[0]}; + my $section; + + foreach $section (@{$args{'sectionlist'}}) { + print "<section>\n"; + print "<h1>$section</h1>\n"; + print "<p>\n"; + output_highlight($args{'sections'}{$section}); + print "</p>\n"; + print "</section>\n"; + } +} + +# output enum in html5 +sub output_enum_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $html5id; + + $html5id = $args{'enum'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"enum\" id=\"enum:". $html5id . "\">"; + print "<h1>enum " . $args{'enum'} . "</h1>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"keyword\">enum</span> "; + print "<span class=\"identifier\">" . $args{'enum'} . "</span> {"; + print "</li>\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + print "<span class=\"param\">" . $parameter . "</span>"; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "</li>\n"; + } + print "<li>};</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Constants</h1>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output typedef in html5 +sub output_typedef_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $html5id; + + $html5id = $args{'typedef'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n"; + print "<h1>typedef " . $args{'typedef'} . "</h1>\n"; + + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"keyword\">typedef</span> "; + print "<span class=\"identifier\">" . $args{'typedef'} . "</span>"; + print "</li>\n"; + print "</ol>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output struct in html5 +sub output_struct_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $html5id; + + $html5id = $args{'struct'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n"; + print "<hgroup>\n"; + print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>"; + print "<h2>". $args{'purpose'} . "</h2>\n"; + print "</hgroup>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"type\">" . $args{'type'} . "</span> "; + print "<span class=\"identifier\">" . $args{'struct'} . "</span> {"; + print "</li>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + if ($parameter =~ /^#/) { + print "<span class=\"param\">" . $parameter ."</span>\n"; + print "</li>\n"; + next; + } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"type\">)</span> "; + print "(<span class=\"args\">$2</span>);"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"bits\">$2</span>;"; + } else { + print "<span class=\"type\">$type</span> "; + print "<span class=\"param\">$parameter</span>;"; + } + print "</li>\n"; + } + print "<li>};</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Members</h1>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output function in html5 +sub output_function_html5(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $html5id; + + $html5id = $args{'function'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"function\" id=\"func:". $html5id . "\">\n"; + print "<hgroup>\n"; + print "<h1>" . $args{'function'} . "</h1>"; + print "<h2>" . $args{'purpose'} . "</h2>\n"; + print "</hgroup>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"type\">" . $args{'functiontype'} . "</span> "; + print "<span class=\"identifier\">" . $args{'function'} . "</span> ("; + print "</li>"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"type\">)</span> "; + print "(<span class=\"args\">$2</span>)"; + } else { + print "<span class=\"type\">$type</span> "; + print "<span class=\"param\">$parameter</span>"; + } + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "</li>\n"; + } + print "<li>)</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Arguments</h1>\n"; + print "<p>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output DOC: block header in html5 +sub output_blockhead_html5(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $html5id; + + foreach $section (@{$args{'sectionlist'}}) { + $html5id = $section; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n"; + print "<h1>$section</h1>\n"; + print "<p>\n"; + output_highlight($args{'sections'}{$section}); + print "</p>\n"; + } + print "</article>\n"; +} + sub output_section_xml(%) { my %args = %{$_[0]}; my $section; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 00f7512a217f..0d93856a03f4 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -821,6 +821,7 @@ static const char *section_white_list[] = ".debug*", ".zdebug*", /* Compressed debug sections. */ ".GCC-command-line", /* mn10300 */ + ".GCC.command.line", /* record-gcc-switches, non mn10300 */ ".mdebug*", /* alpha, score, mips etc. */ ".pdr", /* alpha, score, mips etc. */ ".stab*", diff --git a/scripts/package/buildtar b/scripts/package/buildtar index d0d748e72915..62d8234f8787 100644 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -28,15 +28,15 @@ case "${1}" in file_ext="" ;; targz-pkg) - compress="gzip -c9" + compress="gzip" file_ext=".gz" ;; tarbz2-pkg) - compress="bzip2 -c9" + compress="bzip2" file_ext=".bz2" ;; tarxz-pkg) - compress="xz -c9" + compress="xz" file_ext=".xz" ;; *) diff --git a/scripts/tags.sh b/scripts/tags.sh index cff8faad73d1..79fdafb0d263 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -154,7 +154,9 @@ exuberant() --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ + --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ + --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ @@ -197,7 +199,9 @@ emacs() --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ - --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ + --regex='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ + --regex='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' diff --git a/security/capability.c b/security/capability.c index a40aac677c72..b14a30c234b8 100644 --- a/security/capability.c +++ b/security/capability.c @@ -74,8 +74,8 @@ static int cap_sb_statfs(struct dentry *dentry) return 0; } -static int cap_sb_mount(char *dev_name, struct path *path, char *type, - unsigned long flags, void *data) +static int cap_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return 0; } diff --git a/security/security.c b/security/security.c index 3724029d0f6d..8dcd4ae10a5f 100644 --- a/security/security.c +++ b/security/security.c @@ -276,8 +276,8 @@ int security_sb_statfs(struct dentry *dentry) return security_ops->sb_statfs(dentry); } -int security_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data) +int security_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return security_ops->sb_mount(dev_name, path, type, flags, data); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 651d8456611a..24ab4148547c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2452,9 +2452,9 @@ static int selinux_sb_statfs(struct dentry *dentry) return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } -static int selinux_mount(char *dev_name, +static int selinux_mount(const char *dev_name, struct path *path, - char *type, + const char *type, unsigned long flags, void *data) { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 2874c7316783..38be92ce901e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -408,8 +408,8 @@ static int smack_sb_statfs(struct dentry *dentry) * Returns 0 if current can write the floor of the filesystem * being mounted on, an error code otherwise. */ -static int smack_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data) +static int smack_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { struct superblock_smack *sbp = path->dentry->d_sb->s_security; struct smk_audit_info ad; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index af010b62d544..d4f166bc3508 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -970,7 +970,7 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, const u8 index); int tomoyo_mkdev_perm(const u8 operation, struct path *path, const unsigned int mode, unsigned int dev); -int tomoyo_mount_permission(char *dev_name, struct path *path, +int tomoyo_mount_permission(const char *dev_name, struct path *path, const char *type, unsigned long flags, void *data_page); int tomoyo_open_control(const u8 type, struct file *file); diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index fe00cdfd0267..390c646013cb 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -71,7 +71,8 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, +static int tomoyo_mount_acl(struct tomoyo_request_info *r, + const char *dev_name, struct path *dir, const char *type, unsigned long flags) { @@ -183,7 +184,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, * * Returns 0 on success, negative value otherwise. */ -int tomoyo_mount_permission(char *dev_name, struct path *path, +int tomoyo_mount_permission(const char *dev_name, struct path *path, const char *type, unsigned long flags, void *data_page) { diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index d88eb3a046ed..a2ee362546ab 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -408,8 +408,8 @@ static int tomoyo_path_chroot(struct path *path) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data) +static int tomoyo_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return tomoyo_mount_permission(dev_name, path, type, flags, data); } diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c index 24c430f721d4..672af8b56542 100644 --- a/sound/oss/waveartist.c +++ b/sound/oss/waveartist.c @@ -1482,9 +1482,9 @@ vnc_mute_spkr(wavnc_info *devc) { unsigned long flags; - spin_lock_irqsave(&nw_gpio_lock, flags); + raw_spin_lock_irqsave(&nw_gpio_lock, flags); nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE); - spin_unlock_irqrestore(&nw_gpio_lock, flags); + raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); } static void diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c0ab72cbeed1..70d4848b5cd0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5168,6 +5168,8 @@ EXPORT_SYMBOL_HDA(snd_hda_resume); */ void *snd_array_new(struct snd_array *array) { + if (snd_BUG_ON(!array->elem_size)) + return NULL; if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; int size = (num + 1) * array->elem_size; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f09ff6c14041..6833835a218b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -554,7 +554,6 @@ enum { #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ -#define AZX_DCAPS_POSFIX_COMBO (1 << 24) /* Use COMBO as default */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ /* quirks for ATI SB / AMD Hudson */ @@ -2858,10 +2857,6 @@ static int __devinit check_position_fix(struct azx *chip, int fix) snd_printd(SFX "Using LPIB position fix\n"); return POS_FIX_LPIB; } - if (chip->driver_caps & AZX_DCAPS_POSFIX_COMBO) { - snd_printd(SFX "Using COMBO position fix\n"); - return POS_FIX_COMBO; - } return POS_FIX_AUTO; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index fcfc9f0a056b..61a71131711c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -897,7 +897,7 @@ static int build_digital_input(struct hda_codec *codec) * HP/SPK/SPDIF */ -static void cs_automute(struct hda_codec *codec) +static void cs_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -973,7 +973,7 @@ static void cs_automute(struct hda_codec *codec) * Switch max 3 inputs of a single ADC (nid 3) */ -static void cs_automic(struct hda_codec *codec) +static void cs_automic(struct hda_codec *codec, struct hda_jack_tbl *tbl) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -1035,7 +1035,7 @@ static void init_output(struct hda_codec *codec) if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable(codec, nid, HP_EVENT); + snd_hda_jack_detect_enable_callback(codec, nid, HP_EVENT, cs_automute); spec->hp_detect = 1; } } @@ -1046,7 +1046,7 @@ static void init_output(struct hda_codec *codec) /* SPDIF is enabled on presence detect for CS421x */ if (spec->hp_detect || spec->spdif_detect) - cs_automute(codec); + cs_automute(codec, NULL); } static void init_input(struct hda_codec *codec) @@ -1070,13 +1070,13 @@ static void init_input(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(spec->adc_idx[i])); if (spec->mic_detect && spec->automic_idx == i) - snd_hda_jack_detect_enable(codec, pin, MIC_EVENT); + snd_hda_jack_detect_enable_callback(codec, pin, MIC_EVENT, cs_automic); } /* CS420x has multiple ADC, CS421x has single ADC */ if (spec->vendor_nid == CS420X_VENDOR_NID) { change_cur_input(codec, spec->cur_input, 1); if (spec->mic_detect) - cs_automic(codec); + cs_automic(codec, NULL); coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ if (is_active_pin(codec, CS_DMIC2_PIN_NID)) @@ -1089,7 +1089,7 @@ static void init_input(struct hda_codec *codec) cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); } else { if (spec->mic_detect) - cs_automic(codec); + cs_automic(codec, NULL); else { spec->cur_adc = spec->adc_nid[spec->cur_input]; cs_update_input_select(codec); @@ -1243,28 +1243,16 @@ static void cs_free(struct hda_codec *codec) struct cs_spec *spec = codec->spec; kfree(spec->capture_bind[0]); kfree(spec->capture_bind[1]); + snd_hda_gen_free(&spec->gen); kfree(codec->spec); } -static void cs_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (snd_hda_jack_get_action(codec, res >> 26)) { - case HP_EVENT: - cs_automute(codec); - break; - case MIC_EVENT: - cs_automic(codec); - break; - } - snd_hda_jack_report_sync(codec); -} - static const struct hda_codec_ops cs_patch_ops = { .build_controls = cs_build_controls, .build_pcms = cs_build_pcms, .init = cs_init, .free = cs_free, - .unsol_event = cs_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, }; static int cs_parse_auto_config(struct hda_codec *codec) @@ -1439,6 +1427,7 @@ static int patch_cs420x(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; + snd_hda_gen_init(&spec->gen); spec->vendor_nid = CS420X_VENDOR_NID; @@ -1457,7 +1446,7 @@ static int patch_cs420x(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } @@ -1674,7 +1663,7 @@ static void init_cs421x_digital(struct hda_codec *codec) if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable(codec, nid, SPDIF_EVENT); + snd_hda_jack_detect_enable_callback(codec, nid, SPDIF_EVENT, cs_automute); spec->spdif_detect = 1; } } @@ -1889,21 +1878,6 @@ static int cs421x_build_controls(struct hda_codec *codec) return 0; } -static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (snd_hda_jack_get_action(codec, res >> 26)) { - case HP_EVENT: - case SPDIF_EVENT: - cs_automute(codec); - break; - - case MIC_EVENT: - cs_automic(codec); - break; - } - snd_hda_jack_report_sync(codec); -} - static int parse_cs421x_input(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -1977,7 +1951,7 @@ static struct hda_codec_ops cs421x_patch_ops = { .build_pcms = cs_build_pcms, .init = cs421x_init, .free = cs_free, - .unsol_event = cs421x_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .suspend = cs421x_suspend, #endif @@ -1992,6 +1966,7 @@ static int patch_cs4210(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; + snd_hda_gen_init(&spec->gen); spec->vendor_nid = CS4210_VENDOR_NID; @@ -2017,7 +1992,7 @@ static int patch_cs4210(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } @@ -2031,6 +2006,7 @@ static int patch_cs4213(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; + snd_hda_gen_init(&spec->gen); spec->vendor_nid = CS4213_VENDOR_NID; @@ -2042,7 +2018,7 @@ static int patch_cs4213(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8568aee56e2d..8253b4eeb6a1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -611,6 +611,8 @@ static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack { struct alc_spec *spec = codec->spec; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + return; /* check LO jack only when it's different from HP */ if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) return; @@ -4245,6 +4247,7 @@ static void alc_auto_init_std(struct hda_codec *codec) ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) static const struct snd_pci_quirk beep_white_list[] = { + SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fe163547f906..770013ff556f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -104,6 +104,7 @@ enum { STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_MIC_LED, + STAC_92HD83XXX_HEADSET_JACK, STAC_92HD83XXX_MODELS }; @@ -204,6 +205,7 @@ struct sigmatel_spec { unsigned int check_volume_offset:1; unsigned int auto_mic:1; unsigned int linear_tone_beep:1; + unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */ /* gpio lines */ unsigned int eapd_mask; @@ -1684,6 +1686,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_HP_LED] = "hp-led", [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led", + [STAC_92HD83XXX_HEADSET_JACK] = "headset-jack", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1694,6 +1697,24 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD83XXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, "unknown Dell", STAC_DELL_S14), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0532, + "Dell Latitude E6230", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0533, + "Dell Latitude E6330", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0534, + "Dell Latitude E6430", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0535, + "Dell Latitude E6530", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053c, + "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053d, + "Dell Latitude E5530", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0549, + "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x057d, + "Dell Latitude E6430s", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0584, + "Dell Latitude E6430U", STAC_92HD83XXX_HEADSET_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028, "Dell Vostro 3500", STAC_DELL_VOSTRO_3500), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656, @@ -2855,6 +2876,9 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, char name[22]; if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { + if (spec->headset_jack && snd_hda_get_input_pin_attr(def_conf) + != INPUT_PIN_ATTR_DOCK) + return 0; if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD && nid == spec->line_switch) control = STAC_CTL_WIDGET_IO_SWITCH; @@ -5626,6 +5650,9 @@ again: case STAC_92HD83XXX_HP_MIC_LED: spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ break; + case STAC_92HD83XXX_HEADSET_JACK: + spec->headset_jack = 1; + break; } if (find_mute_led_cfg(codec, default_polarity)) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 5a45a912aedc..72a2f60b087c 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -118,6 +118,8 @@ enum { }; struct via_spec { + struct hda_gen_spec gen; + /* codec parameterization */ const struct snd_kcontrol_new *mixers[6]; unsigned int num_mixers; @@ -246,6 +248,7 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) /* VT1708BCE & VT1708S are almost same */ if (spec->codec_type == VT1708BCE) spec->codec_type = VT1708S; + snd_hda_gen_init(&spec->gen); return spec; } @@ -299,7 +302,6 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 -#define VIA_GPIO_EVENT 0x02 #define VIA_LINE_EVENT 0x03 enum { @@ -1628,6 +1630,7 @@ static void via_free(struct hda_codec *codec) vt1708_stop_hp_work(spec); kfree(spec->bind_cap_vol); kfree(spec->bind_cap_sw); + snd_hda_gen_free(&spec->gen); kfree(spec); } @@ -1685,69 +1688,6 @@ static void via_hp_automute(struct hda_codec *codec) via_line_automute(codec, present); } -static void via_gpio_control(struct hda_codec *codec) -{ - unsigned int gpio_data; - unsigned int vol_counter; - unsigned int vol; - unsigned int master_vol; - - struct via_spec *spec = codec->spec; - - gpio_data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0) & 0x03; - - vol_counter = (snd_hda_codec_read(codec, codec->afg, 0, - 0xF84, 0) & 0x3F0000) >> 16; - - vol = vol_counter & 0x1F; - master_vol = snd_hda_codec_read(codec, 0x1A, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT); - - if (gpio_data == 0x02) { - /* unmute line out */ - snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], - PIN_OUT); - if (vol_counter & 0x20) { - /* decrease volume */ - if (vol > master_vol) - vol = master_vol; - snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, - 0, HDA_AMP_VOLMASK, - master_vol-vol); - } else { - /* increase volume */ - snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0, - HDA_AMP_VOLMASK, - ((master_vol+vol) > 0x2A) ? 0x2A : - (master_vol+vol)); - } - } else if (!(gpio_data & 0x02)) { - /* mute line out */ - snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0); - } -} - -/* unsolicited event for jack sensing */ -static void via_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - res = snd_hda_jack_get_action(codec, res); - - if (res & VIA_JACK_EVENT) - set_widgets_power_state(codec); - - res &= ~VIA_JACK_EVENT; - - if (res == VIA_HP_EVENT || res == VIA_LINE_EVENT) - via_hp_automute(codec); - else if (res == VIA_GPIO_EVENT) - via_gpio_control(codec); - snd_hda_jack_report_sync(codec); -} - #ifdef CONFIG_PM static int via_suspend(struct hda_codec *codec) { @@ -1783,7 +1723,7 @@ static const struct hda_codec_ops via_patch_ops = { .build_pcms = via_build_pcms, .init = via_init, .free = via_free, - .unsol_event = via_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .suspend = via_suspend, .check_power_status = via_check_power_status, @@ -2761,6 +2701,17 @@ static void via_auto_init_dig_in(struct hda_codec *codec) snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN); } +static void via_jack_output_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +{ + set_widgets_power_state(codec); + via_hp_automute(codec); +} + +static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +{ + set_widgets_power_state(codec); +} + /* initialize the unsolicited events */ static void via_auto_init_unsol_event(struct hda_codec *codec) { @@ -2768,26 +2719,31 @@ static void via_auto_init_unsol_event(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int ev; int i; + hda_jack_callback cb; if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_jack_detect_enable(codec, cfg->hp_pins[0], - VIA_HP_EVENT | VIA_JACK_EVENT); + snd_hda_jack_detect_enable_callback(codec, cfg->hp_pins[0], + VIA_HP_EVENT | VIA_JACK_EVENT, + via_jack_output_event); if (cfg->speaker_pins[0]) ev = VIA_LINE_EVENT; else ev = 0; + cb = ev ? via_jack_output_event : via_jack_powerstate_event; + for (i = 0; i < cfg->line_outs; i++) { if (cfg->line_out_pins[i] && is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_jack_detect_enable(codec, cfg->line_out_pins[i], - ev | VIA_JACK_EVENT); + snd_hda_jack_detect_enable_callback(codec, cfg->line_out_pins[i], + ev | VIA_JACK_EVENT, cb); } for (i = 0; i < cfg->num_inputs; i++) { if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_jack_detect_enable(codec, cfg->inputs[i].pin, - VIA_JACK_EVENT); + snd_hda_jack_detect_enable_callback(codec, cfg->inputs[i].pin, + VIA_JACK_EVENT, + via_jack_powerstate_event); } } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index d73ac9bc4272..88d8cebbb244 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2780,6 +2780,52 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* Tascam US122 MKII - playback-only support */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = 0x8021, + .bInterfaceClass = USB_CLASS_AUDIO, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "TASCAM", + .product_name = "US122 MKII", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x02, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } + }, + { + .ifnum = -1 + } + } + } +}, /* Microsoft XboxLive Headset/Xbox Communicator */ { diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 86258c2a2c23..247264502fb7 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -45,6 +45,8 @@ include config/utilities.mak # # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf # backtrace post unwind. +# +# Define NO_BACKTRACE if you do not want stack backtrace debug feature $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) @@ -185,7 +187,7 @@ strip-libs = $(filter-out -l%,$(1)) PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py -$(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) +$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ mkdir -p $(OUTPUT)python && \ @@ -268,6 +270,7 @@ LIB_H += util/include/linux/magic.h LIB_H += util/include/linux/poison.h LIB_H += util/include/linux/prefetch.h LIB_H += util/include/linux/rbtree.h +LIB_H += util/include/linux/rbtree_augmented.h LIB_H += util/include/linux/string.h LIB_H += util/include/linux/types.h LIB_H += util/include/linux/linkage.h @@ -446,20 +449,6 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) -# Files needed for the python binding, perf.so -# pyrf is just an internal name needed for all those wrappers. -# This has to be in sync with what is in the 'sources' variable in -# tools/perf/util/setup.py - -PYRF_OBJS += $(OUTPUT)util/cpumap.o -PYRF_OBJS += $(OUTPUT)util/ctype.o -PYRF_OBJS += $(OUTPUT)util/evlist.o -PYRF_OBJS += $(OUTPUT)util/evsel.o -PYRF_OBJS += $(OUTPUT)util/python.o -PYRF_OBJS += $(OUTPUT)util/thread_map.o -PYRF_OBJS += $(OUTPUT)util/util.o -PYRF_OBJS += $(OUTPUT)util/xyarray.o - # # Platform specific tweaks # @@ -486,7 +475,13 @@ ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) NO_DWARF := 1 NO_DEMANGLE := 1 endif -endif +else + FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) + ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) + msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); + NO_DWARF := 1 + endif # Dwarf support +endif # SOURCE_LIBELF endif # NO_LIBELF ifndef NO_LIBUNWIND @@ -511,8 +506,6 @@ ifneq ($(OUTPUT),) endif ifdef NO_LIBELF -BASIC_CFLAGS += -DNO_LIBELF_SUPPORT - EXTLIBS := $(filter-out -lelf,$(EXTLIBS)) # Remove ELF/DWARF dependent codes @@ -527,17 +520,12 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS)) LIB_OBJS += $(OUTPUT)util/symbol-minimal.o else # NO_LIBELF +BASIC_CFLAGS += -DLIBELF_SUPPORT -ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) - BASIC_CFLAGS += -DLIBELF_NO_MMAP +ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) + BASIC_CFLAGS += -DLIBELF_MMAP endif -FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) -ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) - msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); - NO_DWARF := 1 -endif # Dwarf support - ifndef NO_DWARF ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); @@ -550,38 +538,33 @@ endif # PERF_HAVE_DWARF_REGS endif # NO_DWARF endif # NO_LIBELF -ifdef NO_LIBUNWIND - BASIC_CFLAGS += -DNO_LIBUNWIND_SUPPORT -else +ifndef NO_LIBUNWIND + BASIC_CFLAGS += -DLIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS) BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS) LIB_OBJS += $(OUTPUT)util/unwind.o endif -ifdef NO_LIBAUDIT - BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT -else +ifndef NO_LIBAUDIT FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); - BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT else + BASIC_CFLAGS += -DLIBAUDIT_SUPPORT BUILTIN_OBJS += $(OUTPUT)builtin-trace.o EXTLIBS += -laudit endif endif -ifdef NO_NEWT - BASIC_CFLAGS += -DNO_NEWT_SUPPORT -else +ifndef NO_NEWT FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); - BASIC_CFLAGS += -DNO_NEWT_SUPPORT else # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h BASIC_CFLAGS += -I/usr/include/slang + BASIC_CFLAGS += -DNEWT_SUPPORT EXTLIBS += -lnewt -lslang LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/browser.o @@ -603,17 +586,15 @@ else endif endif -ifdef NO_GTK2 - BASIC_CFLAGS += -DNO_GTK2_SUPPORT -else +ifndef NO_GTK2 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); - BASIC_CFLAGS += -DNO_GTK2_SUPPORT else ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR endif + BASIC_CFLAGS += -DGTK2_SUPPORT BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) LIB_OBJS += $(OUTPUT)ui/gtk/browser.o @@ -621,7 +602,7 @@ else LIB_OBJS += $(OUTPUT)ui/gtk/util.o LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o # Make sure that it'd be included only once. - ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) + ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/util.o endif @@ -762,23 +743,18 @@ ifeq ($(NO_PERF_REGS),0) ifeq ($(ARCH),x86) LIB_H += arch/x86/include/perf_regs.h endif -else - BASIC_CFLAGS += -DNO_PERF_REGS + BASIC_CFLAGS += -DHAVE_PERF_REGS endif -ifdef NO_STRLCPY - BASIC_CFLAGS += -DNO_STRLCPY -else - ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y) - BASIC_CFLAGS += -DNO_STRLCPY +ifndef NO_STRLCPY + ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y) + BASIC_CFLAGS += -DHAVE_STRLCPY endif endif -ifdef NO_BACKTRACE - BASIC_CFLAGS += -DNO_BACKTRACE -else - ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y) - BASIC_CFLAGS += -DNO_BACKTRACE +ifndef NO_BACKTRACE + ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y) + BASIC_CFLAGS += -DBACKTRACE_SUPPORT endif endif @@ -906,7 +882,7 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS - $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< diff --git a/tools/perf/bash_completion b/tools/perf/bash_completion index 1958fa539d0f..56e6a12aab59 100644 --- a/tools/perf/bash_completion +++ b/tools/perf/bash_completion @@ -1,23 +1,59 @@ # perf completion +function_exists() +{ + declare -F $1 > /dev/null + return $? +} + +function_exists __ltrim_colon_completions || +__ltrim_colon_completions() +{ + if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then + # Remove colon-word prefix from COMPREPLY items + local colon_word=${1%${1##*:}} + local i=${#COMPREPLY[*]} + while [[ $((--i)) -ge 0 ]]; do + COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} + done + fi +} + have perf && _perf() { - local cur cmd + local cur prev cmd COMPREPLY=() - _get_comp_words_by_ref cur prev + if function_exists _get_comp_words_by_ref; then + _get_comp_words_by_ref -n : cur prev + else + cur=$(_get_cword :) + prev=${COMP_WORDS[COMP_CWORD-1]} + fi cmd=${COMP_WORDS[0]} - # List perf subcommands + # List perf subcommands or long options if [ $COMP_CWORD -eq 1 ]; then - cmds=$($cmd --list-cmds) - COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) + if [[ $cur == --* ]]; then + COMPREPLY=( $( compgen -W '--help --version \ + --exec-path --html-path --paginate --no-pager \ + --perf-dir --work-tree --debugfs-dir' -- "$cur" ) ) + else + cmds=$($cmd --list-cmds) + COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) + fi # List possible events for -e option elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then - cmds=$($cmd list --raw-dump) - COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) + evts=$($cmd list --raw-dump) + COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) + __ltrim_colon_completions $cur + # List long option names + elif [[ $cur == --* ]]; then + subcmd=${COMP_WORDS[1]} + opts=$($cmd $subcmd --list-opts) + COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) # Fall down to list regular files else _filedir diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 83654557e108..d37e077f4b14 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -15,22 +15,6 @@ #include "util/strlist.h" #include "util/symbol.h" -static char const *add_name_list_str, *remove_name_list_str; - -static const char * const buildid_cache_usage[] = { - "perf buildid-cache [<options>]", - NULL -}; - -static const struct option buildid_cache_options[] = { - OPT_STRING('a', "add", &add_name_list_str, - "file list", "file(s) to add"), - OPT_STRING('r', "remove", &remove_name_list_str, "file list", - "file(s) to remove"), - OPT_INCR('v', "verbose", &verbose, "be more verbose"), - OPT_END() -}; - static int build_id_cache__add_file(const char *filename, const char *debugdir) { char sbuild_id[BUILD_ID_SIZE * 2 + 1]; @@ -51,8 +35,8 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir) return err; } -static int build_id_cache__remove_file(const char *filename __maybe_unused, - const char *debugdir __maybe_unused) +static int build_id_cache__remove_file(const char *filename, + const char *debugdir) { u8 build_id[BUILD_ID_SIZE]; char sbuild_id[BUILD_ID_SIZE * 2 + 1]; @@ -73,11 +57,34 @@ static int build_id_cache__remove_file(const char *filename __maybe_unused, return err; } -static int __cmd_buildid_cache(void) +int cmd_buildid_cache(int argc, const char **argv, + const char *prefix __maybe_unused) { struct strlist *list; struct str_node *pos; char debugdir[PATH_MAX]; + char const *add_name_list_str = NULL, + *remove_name_list_str = NULL; + const struct option buildid_cache_options[] = { + OPT_STRING('a', "add", &add_name_list_str, + "file list", "file(s) to add"), + OPT_STRING('r', "remove", &remove_name_list_str, "file list", + "file(s) to remove"), + OPT_INCR('v', "verbose", &verbose, "be more verbose"), + OPT_END() + }; + const char * const buildid_cache_usage[] = { + "perf buildid-cache [<options>]", + NULL + }; + + argc = parse_options(argc, argv, buildid_cache_options, + buildid_cache_usage, 0); + + if (symbol__init() < 0) + return -1; + + setup_pager(); snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); @@ -119,16 +126,3 @@ static int __cmd_buildid_cache(void) return 0; } - -int cmd_buildid_cache(int argc, const char **argv, - const char *prefix __maybe_unused) -{ - argc = parse_options(argc, argv, buildid_cache_options, - buildid_cache_usage, 0); - - if (symbol__init() < 0) - return -1; - - setup_pager(); - return __cmd_buildid_cache(); -} diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 1159feeebb19..a0e94fffa03e 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -16,27 +16,6 @@ #include "util/session.h" #include "util/symbol.h" -static const char *input_name; -static bool force; -static bool show_kernel; -static bool with_hits; - -static const char * const buildid_list_usage[] = { - "perf buildid-list [<options>]", - NULL -}; - -static const struct option options[] = { - OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), - OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), - OPT_INCR('v', "verbose", &verbose, - "be more verbose"), - OPT_END() -}; - static int sysfs__fprintf_build_id(FILE *fp) { u8 kallsyms_build_id[BUILD_ID_SIZE]; @@ -65,7 +44,8 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) return fprintf(fp, "%s\n", sbuild_id); } -static int perf_session__list_build_ids(void) +static int perf_session__list_build_ids(const char *input_name, + bool force, bool with_hits) { struct perf_session *session; @@ -95,18 +75,31 @@ out: return 0; } -static int __cmd_buildid_list(void) -{ - if (show_kernel) - return sysfs__fprintf_build_id(stdout); - - return perf_session__list_build_ids(); -} - int cmd_buildid_list(int argc, const char **argv, const char *prefix __maybe_unused) { + bool show_kernel = false; + bool with_hits = false; + bool force = false; + const char *input_name = NULL; + const struct option options[] = { + OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), + OPT_STRING('i', "input", &input_name, "file", "input file name"), + OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), + OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), + OPT_INCR('v', "verbose", &verbose, "be more verbose"), + OPT_END() + }; + const char * const buildid_list_usage[] = { + "perf buildid-list [<options>]", + NULL + }; + argc = parse_options(argc, argv, options, buildid_list_usage, 0); setup_pager(); - return __cmd_buildid_list(); + + if (show_kernel) + return sysfs__fprintf_build_id(stdout); + + return perf_session__list_build_ids(input_name, force, with_hits); } diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 761f4197a9e2..a0b531c14b97 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -70,8 +70,8 @@ static struct perf_tool tool = { .ordering_requires_timestamps = true, }; -static void perf_session__insert_hist_entry_by_name(struct rb_root *root, - struct hist_entry *he) +static void insert_hist_entry_by_name(struct rb_root *root, + struct hist_entry *he) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; @@ -90,7 +90,7 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root, rb_insert_color(&he->rb_node, root); } -static void hists__resort_entries(struct hists *self) +static void hists__name_resort(struct hists *self, bool sort) { unsigned long position = 1; struct rb_root tmp = RB_ROOT; @@ -100,12 +100,16 @@ static void hists__resort_entries(struct hists *self) struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); next = rb_next(&n->rb_node); - rb_erase(&n->rb_node, &self->entries); n->position = position++; - perf_session__insert_hist_entry_by_name(&tmp, n); + + if (sort) { + rb_erase(&n->rb_node, &self->entries); + insert_hist_entry_by_name(&tmp, n); + } } - self->entries = tmp; + if (sort) + self->entries = tmp; } static struct hist_entry *hists__find_entry(struct hists *self, @@ -121,7 +125,7 @@ static struct hist_entry *hists__find_entry(struct hists *self, n = n->rb_left; else if (cmp > 0) n = n->rb_right; - else + else return iter; } @@ -150,6 +154,24 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, return NULL; } +static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) +{ + struct perf_evsel *evsel; + + list_for_each_entry(evsel, &evlist->entries, node) { + struct hists *hists = &evsel->hists; + + hists__output_resort(hists); + + /* + * The hists__name_resort only sets possition + * if name is false. + */ + if (name || ((!name) && show_displacement)) + hists__name_resort(hists, name); + } +} + static int __cmd_diff(void) { int ret, i; @@ -176,15 +198,8 @@ static int __cmd_diff(void) evlist_old = older->evlist; evlist_new = newer->evlist; - list_for_each_entry(evsel, &evlist_new->entries, node) - hists__output_resort(&evsel->hists); - - list_for_each_entry(evsel, &evlist_old->entries, node) { - hists__output_resort(&evsel->hists); - - if (show_displacement) - hists__resort_entries(&evsel->hists); - } + perf_evlist__resort_hists(evlist_old, true); + perf_evlist__resort_hists(evlist_new, false); list_for_each_entry(evsel, &evlist_new->entries, node) { struct perf_evsel *evsel_old; @@ -199,8 +214,7 @@ static int __cmd_diff(void) first = false; hists__match(&evsel_old->hists, &evsel->hists); - hists__fprintf(&evsel->hists, &evsel_old->hists, - show_displacement, true, 0, 0, stdout); + hists__fprintf(&evsel->hists, true, 0, 0, stdout); } out_delete: @@ -242,6 +256,21 @@ static const struct option options[] = { OPT_END() }; +static void ui_init(void) +{ + perf_hpp__init(); + + /* No overhead column. */ + perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); + + /* Display baseline/delta/displacement columns. */ + perf_hpp__column_enable(PERF_HPP__BASELINE, true); + perf_hpp__column_enable(PERF_HPP__DELTA, true); + + if (show_displacement) + perf_hpp__column_enable(PERF_HPP__DISPL, true); +} + int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) { sort_order = diff__default_sort_order; @@ -264,7 +293,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) if (symbol__init() < 0) return -1; - perf_hpp__init(true, show_displacement); + ui_init(); + setup_sorting(diff_usage, options); setup_pager(); diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 1fb164164fd0..997afb82691b 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -108,23 +108,20 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail return 0; } -static const char * const evlist_usage[] = { - "perf evlist [<options>]", - NULL -}; - int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) { struct perf_attr_details details = { .verbose = false, }; const char *input_name = NULL; const struct option options[] = { - OPT_STRING('i', "input", &input_name, "file", - "Input file name"), - OPT_BOOLEAN('F', "freq", &details.freq, - "Show the sample frequency"), - OPT_BOOLEAN('v', "verbose", &details.verbose, - "Show all event attr details"), - OPT_END() + OPT_STRING('i', "input", &input_name, "file", "Input file name"), + OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), + OPT_BOOLEAN('v', "verbose", &details.verbose, + "Show all event attr details"), + OPT_END() + }; + const char * const evlist_usage[] = { + "perf evlist [<options>]", + NULL }; argc = parse_options(argc, argv, options, evlist_usage, 0); diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 25c8b942ff85..411ee5664e98 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -30,23 +30,6 @@ enum help_format { HELP_FORMAT_WEB, }; -static bool show_all = false; -static enum help_format help_format = HELP_FORMAT_NONE; -static struct option builtin_help_options[] = { - OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), - OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), - OPT_SET_UINT('w', "web", &help_format, "show manual in web browser", - HELP_FORMAT_WEB), - OPT_SET_UINT('i', "info", &help_format, "show info page", - HELP_FORMAT_INFO), - OPT_END(), -}; - -static const char * const builtin_help_usage[] = { - "perf help [--all] [--man|--web|--info] [command]", - NULL -}; - static enum help_format parse_help_format(const char *format) { if (!strcmp(format, "man")) @@ -258,11 +241,13 @@ static int add_man_viewer_info(const char *var, const char *value) static int perf_help_config(const char *var, const char *value, void *cb) { + enum help_format *help_formatp = cb; + if (!strcmp(var, "help.format")) { if (!value) return config_error_nonbool(var); - help_format = parse_help_format(value); - if (help_format == HELP_FORMAT_NONE) + *help_formatp = parse_help_format(value); + if (*help_formatp == HELP_FORMAT_NONE) return -1; return 0; } @@ -428,12 +413,27 @@ static int show_html_page(const char *perf_cmd) int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) { + bool show_all = false; + enum help_format help_format = HELP_FORMAT_NONE; + struct option builtin_help_options[] = { + OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), + OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), + OPT_SET_UINT('w', "web", &help_format, "show manual in web browser", + HELP_FORMAT_WEB), + OPT_SET_UINT('i', "info", &help_format, "show info page", + HELP_FORMAT_INFO), + OPT_END(), + }; + const char * const builtin_help_usage[] = { + "perf help [--all] [--man|--web|--info] [command]", + NULL + }; const char *alias; int rc = 0; load_command_list("perf-", &main_cmds, &other_cmds); - perf_config(perf_help_config, NULL); + perf_config(perf_help_config, &help_format); argc = parse_options(argc, argv, builtin_help_options, builtin_help_usage, 0); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 1eaa6617c814..4688bea95c12 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -14,8 +14,10 @@ #include "util/parse-options.h" -static char const *input_name = "-"; -static bool inject_build_ids; +struct perf_inject { + struct perf_tool tool; + bool build_ids; +}; static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, union perf_event *event, @@ -194,7 +196,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, * account this as unresolved. */ } else { -#ifndef NO_LIBELF_SUPPORT +#ifdef LIBELF_SUPPORT pr_warning("no symbols found in %s, maybe " "install a debug package?\n", al.map->dso->long_name); @@ -208,22 +210,6 @@ repipe: return 0; } -struct perf_tool perf_inject = { - .sample = perf_event__repipe_sample, - .mmap = perf_event__repipe, - .comm = perf_event__repipe, - .fork = perf_event__repipe, - .exit = perf_event__repipe, - .lost = perf_event__repipe, - .read = perf_event__repipe_sample, - .throttle = perf_event__repipe, - .unthrottle = perf_event__repipe, - .attr = perf_event__repipe_attr, - .event_type = perf_event__repipe_event_type_synth, - .tracing_data = perf_event__repipe_tracing_data_synth, - .build_id = perf_event__repipe_op2_synth, -}; - extern volatile int session_done; static void sig_handler(int sig __maybe_unused) @@ -231,56 +217,72 @@ static void sig_handler(int sig __maybe_unused) session_done = 1; } -static int __cmd_inject(void) +static int __cmd_inject(struct perf_inject *inject) { struct perf_session *session; int ret = -EINVAL; signal(SIGINT, sig_handler); - if (inject_build_ids) { - perf_inject.sample = perf_event__inject_buildid; - perf_inject.mmap = perf_event__repipe_mmap; - perf_inject.fork = perf_event__repipe_task; - perf_inject.tracing_data = perf_event__repipe_tracing_data; + if (inject->build_ids) { + inject->tool.sample = perf_event__inject_buildid; + inject->tool.mmap = perf_event__repipe_mmap; + inject->tool.fork = perf_event__repipe_task; + inject->tool.tracing_data = perf_event__repipe_tracing_data; } - session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject); + session = perf_session__new("-", O_RDONLY, false, true, &inject->tool); if (session == NULL) return -ENOMEM; - ret = perf_session__process_events(session, &perf_inject); + ret = perf_session__process_events(session, &inject->tool); perf_session__delete(session); return ret; } -static const char * const report_usage[] = { - "perf inject [<options>]", - NULL -}; - -static const struct option options[] = { - OPT_BOOLEAN('b', "build-ids", &inject_build_ids, - "Inject build-ids into the output stream"), - OPT_INCR('v', "verbose", &verbose, - "be more verbose (show build ids, etc)"), - OPT_END() -}; - int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) { - argc = parse_options(argc, argv, options, report_usage, 0); + struct perf_inject inject = { + .tool = { + .sample = perf_event__repipe_sample, + .mmap = perf_event__repipe, + .comm = perf_event__repipe, + .fork = perf_event__repipe, + .exit = perf_event__repipe, + .lost = perf_event__repipe, + .read = perf_event__repipe_sample, + .throttle = perf_event__repipe, + .unthrottle = perf_event__repipe, + .attr = perf_event__repipe_attr, + .event_type = perf_event__repipe_event_type_synth, + .tracing_data = perf_event__repipe_tracing_data_synth, + .build_id = perf_event__repipe_op2_synth, + }, + }; + const struct option options[] = { + OPT_BOOLEAN('b', "build-ids", &inject.build_ids, + "Inject build-ids into the output stream"), + OPT_INCR('v', "verbose", &verbose, + "be more verbose (show build ids, etc)"), + OPT_END() + }; + const char * const inject_usage[] = { + "perf inject [<options>]", + NULL + }; + + argc = parse_options(argc, argv, options, inject_usage, 0); /* * Any (unrecognized) arguments left? */ if (argc) - usage_with_options(report_usage, options); + usage_with_options(inject_usage, options); if (symbol__init() < 0) return -1; - return __cmd_inject(); + return __cmd_inject(&inject); } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index bc912c68f49a..14bf82f63659 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -21,8 +21,6 @@ struct alloc_stat; typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); -static const char *input_name; - static int alloc_flag; static int caller_flag; @@ -31,8 +29,6 @@ static int caller_lines = -1; static bool raw_ip; -static char default_sort_order[] = "frag,hit,bytes"; - static int *cpunode_map; static int max_cpu_num; @@ -481,7 +477,7 @@ static void sort_result(void) __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); } -static int __cmd_kmem(void) +static int __cmd_kmem(const char *input_name) { int err = -EINVAL; struct perf_session *session; @@ -520,11 +516,6 @@ out_delete: return err; } -static const char * const kmem_usage[] = { - "perf kmem [<options>] {record|stat}", - NULL -}; - static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->ptr < r->ptr) @@ -720,41 +711,17 @@ static int parse_line_opt(const struct option *opt __maybe_unused, return 0; } -static const struct option kmem_options[] = { - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, - "show per-callsite statistics", - parse_caller_opt), - OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, - "show per-allocation statistics", - parse_alloc_opt), - OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", - "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", - parse_sort_opt), - OPT_CALLBACK('l', "line", NULL, "num", - "show n lines", - parse_line_opt), - OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), - OPT_END() -}; - -static const char *record_args[] = { - "record", - "-a", - "-R", - "-f", - "-c", "1", +static int __cmd_record(int argc, const char **argv) +{ + const char * const record_args[] = { + "record", "-a", "-R", "-f", "-c", "1", "-e", "kmem:kmalloc", "-e", "kmem:kmalloc_node", "-e", "kmem:kfree", "-e", "kmem:kmem_cache_alloc", "-e", "kmem:kmem_cache_alloc_node", "-e", "kmem:kmem_cache_free", -}; - -static int __cmd_record(int argc, const char **argv) -{ + }; unsigned int rec_argc, i, j; const char **rec_argv; @@ -775,6 +742,25 @@ static int __cmd_record(int argc, const char **argv) int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) { + const char * const default_sort_order = "frag,hit,bytes"; + const char *input_name = NULL; + const struct option kmem_options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), + OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, + "show per-callsite statistics", parse_caller_opt), + OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, + "show per-allocation statistics", parse_alloc_opt), + OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", + "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", + parse_sort_opt), + OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt), + OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), + OPT_END() + }; + const char * const kmem_usage[] = { + "perf kmem [<options>] {record|stat}", + NULL + }; argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); if (!argc) @@ -793,7 +779,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) if (list_empty(&alloc_sort)) setup_sorting(&alloc_sort, default_sort_order); - return __cmd_kmem(); + return __cmd_kmem(input_name); } else usage_with_options(kmem_usage, kmem_options); diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index a28c9cad9048..260abc535b5b 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -32,16 +32,76 @@ struct event_key { int info; }; +struct kvm_event_stats { + u64 time; + struct stats stats; +}; + +struct kvm_event { + struct list_head hash_entry; + struct rb_node rb; + + struct event_key key; + + struct kvm_event_stats total; + + #define DEFAULT_VCPU_NUM 8 + int max_vcpu; + struct kvm_event_stats *vcpu; +}; + +typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); + +struct kvm_event_key { + const char *name; + key_cmp_fun key; +}; + + +struct perf_kvm; + struct kvm_events_ops { bool (*is_begin_event)(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key); bool (*is_end_event)(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key); - void (*decode_key)(struct event_key *key, char decode[20]); + void (*decode_key)(struct perf_kvm *kvm, struct event_key *key, + char decode[20]); const char *name; }; +struct exit_reasons_table { + unsigned long exit_code; + const char *reason; +}; + +#define EVENTS_BITS 12 +#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) + +struct perf_kvm { + struct perf_tool tool; + struct perf_session *session; + + const char *file_name; + const char *report_event; + const char *sort_key; + int trace_vcpu; + + struct exit_reasons_table *exit_reasons; + int exit_reasons_size; + const char *exit_reasons_isa; + + struct kvm_events_ops *events_ops; + key_cmp_fun compare; + struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; + u64 total_time; + u64 total_count; + + struct rb_root result; +}; + + static void exit_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key) @@ -78,45 +138,35 @@ static bool exit_event_end(struct perf_evsel *evsel, return kvm_entry_event(evsel); } -struct exit_reasons_table { - unsigned long exit_code; - const char *reason; -}; - -struct exit_reasons_table vmx_exit_reasons[] = { +static struct exit_reasons_table vmx_exit_reasons[] = { VMX_EXIT_REASONS }; -struct exit_reasons_table svm_exit_reasons[] = { +static struct exit_reasons_table svm_exit_reasons[] = { SVM_EXIT_REASONS }; -static int cpu_isa; - -static const char *get_exit_reason(u64 exit_code) +static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code) { - int table_size = ARRAY_SIZE(svm_exit_reasons); - struct exit_reasons_table *table = svm_exit_reasons; - - if (cpu_isa == 1) { - table = vmx_exit_reasons; - table_size = ARRAY_SIZE(vmx_exit_reasons); - } + int i = kvm->exit_reasons_size; + struct exit_reasons_table *tbl = kvm->exit_reasons; - while (table_size--) { - if (table->exit_code == exit_code) - return table->reason; - table++; + while (i--) { + if (tbl->exit_code == exit_code) + return tbl->reason; + tbl++; } pr_err("unknown kvm exit code:%lld on %s\n", - (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM"); + (unsigned long long)exit_code, kvm->exit_reasons_isa); return "UNKNOWN"; } -static void exit_event_decode_key(struct event_key *key, char decode[20]) +static void exit_event_decode_key(struct perf_kvm *kvm, + struct event_key *key, + char decode[20]) { - const char *exit_reason = get_exit_reason(key->key); + const char *exit_reason = get_exit_reason(kvm, key->key); scnprintf(decode, 20, "%s", exit_reason); } @@ -128,11 +178,11 @@ static struct kvm_events_ops exit_events = { .name = "VM-EXIT" }; - /* - * For the mmio events, we treat: - * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry - * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). - */ +/* + * For the mmio events, we treat: + * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry + * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). + */ static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key) { @@ -178,7 +228,9 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, return false; } -static void mmio_event_decode_key(struct event_key *key, char decode[20]) +static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused, + struct event_key *key, + char decode[20]) { scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); @@ -219,7 +271,9 @@ static bool ioport_event_end(struct perf_evsel *evsel, return kvm_entry_event(evsel); } -static void ioport_event_decode_key(struct event_key *key, char decode[20]) +static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused, + struct event_key *key, + char decode[20]) { scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, key->info ? "POUT" : "PIN"); @@ -232,64 +286,37 @@ static struct kvm_events_ops ioport_events = { .name = "IO Port Access" }; -static const char *report_event = "vmexit"; -struct kvm_events_ops *events_ops; - -static bool register_kvm_events_ops(void) +static bool register_kvm_events_ops(struct perf_kvm *kvm) { bool ret = true; - if (!strcmp(report_event, "vmexit")) - events_ops = &exit_events; - else if (!strcmp(report_event, "mmio")) - events_ops = &mmio_events; - else if (!strcmp(report_event, "ioport")) - events_ops = &ioport_events; + if (!strcmp(kvm->report_event, "vmexit")) + kvm->events_ops = &exit_events; + else if (!strcmp(kvm->report_event, "mmio")) + kvm->events_ops = &mmio_events; + else if (!strcmp(kvm->report_event, "ioport")) + kvm->events_ops = &ioport_events; else { - pr_err("Unknown report event:%s\n", report_event); + pr_err("Unknown report event:%s\n", kvm->report_event); ret = false; } return ret; } -struct kvm_event_stats { - u64 time; - struct stats stats; -}; - -struct kvm_event { - struct list_head hash_entry; - struct rb_node rb; - - struct event_key key; - - struct kvm_event_stats total; - - #define DEFAULT_VCPU_NUM 8 - int max_vcpu; - struct kvm_event_stats *vcpu; -}; - struct vcpu_event_record { int vcpu_id; u64 start_time; struct kvm_event *last_event; }; -#define EVENTS_BITS 12 -#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) - -static u64 total_time; -static u64 total_count; -static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; -static void init_kvm_event_record(void) +static void init_kvm_event_record(struct perf_kvm *kvm) { int i; for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) - INIT_LIST_HEAD(&kvm_events_cache[i]); + INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); } static int kvm_events_hash_fn(u64 key) @@ -333,14 +360,15 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key) return event; } -static struct kvm_event *find_create_kvm_event(struct event_key *key) +static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm, + struct event_key *key) { struct kvm_event *event; struct list_head *head; BUG_ON(key->key == INVALID_KEY); - head = &kvm_events_cache[kvm_events_hash_fn(key->key)]; + head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; list_for_each_entry(event, head, hash_entry) if (event->key.key == key->key && event->key.info == key->info) return event; @@ -353,13 +381,14 @@ static struct kvm_event *find_create_kvm_event(struct event_key *key) return event; } -static bool handle_begin_event(struct vcpu_event_record *vcpu_record, +static bool handle_begin_event(struct perf_kvm *kvm, + struct vcpu_event_record *vcpu_record, struct event_key *key, u64 timestamp) { struct kvm_event *event = NULL; if (key->key != INVALID_KEY) - event = find_create_kvm_event(key); + event = find_create_kvm_event(kvm, key); vcpu_record->last_event = event; vcpu_record->start_time = timestamp; @@ -396,8 +425,10 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, return true; } -static bool handle_end_event(struct vcpu_event_record *vcpu_record, - struct event_key *key, u64 timestamp) +static bool handle_end_event(struct perf_kvm *kvm, + struct vcpu_event_record *vcpu_record, + struct event_key *key, + u64 timestamp) { struct kvm_event *event; u64 time_begin, time_diff; @@ -419,7 +450,7 @@ static bool handle_end_event(struct vcpu_event_record *vcpu_record, return true; if (!event) - event = find_create_kvm_event(key); + event = find_create_kvm_event(kvm, key); if (!event) return false; @@ -455,7 +486,9 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread, return thread->priv; } -static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, +static bool handle_kvm_event(struct perf_kvm *kvm, + struct thread *thread, + struct perf_evsel *evsel, struct perf_sample *sample) { struct vcpu_event_record *vcpu_record; @@ -465,22 +498,15 @@ static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, if (!vcpu_record) return true; - if (events_ops->is_begin_event(evsel, sample, &key)) - return handle_begin_event(vcpu_record, &key, sample->time); + if (kvm->events_ops->is_begin_event(evsel, sample, &key)) + return handle_begin_event(kvm, vcpu_record, &key, sample->time); - if (events_ops->is_end_event(evsel, sample, &key)) - return handle_end_event(vcpu_record, &key, sample->time); + if (kvm->events_ops->is_end_event(evsel, sample, &key)) + return handle_end_event(kvm, vcpu_record, &key, sample->time); return true; } -typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); -struct kvm_event_key { - const char *name; - key_cmp_fun key; -}; - -static int trace_vcpu = -1; #define GET_EVENT_KEY(func, field) \ static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ { \ @@ -515,29 +541,25 @@ static struct kvm_event_key keys[] = { { NULL, NULL } }; -static const char *sort_key = "sample"; -static key_cmp_fun compare; - -static bool select_key(void) +static bool select_key(struct perf_kvm *kvm) { int i; for (i = 0; keys[i].name; i++) { - if (!strcmp(keys[i].name, sort_key)) { - compare = keys[i].key; + if (!strcmp(keys[i].name, kvm->sort_key)) { + kvm->compare = keys[i].key; return true; } } - pr_err("Unknown compare key:%s\n", sort_key); + pr_err("Unknown compare key:%s\n", kvm->sort_key); return false; } -static struct rb_root result; -static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, - int vcpu) +static void insert_to_result(struct rb_root *result, struct kvm_event *event, + key_cmp_fun bigger, int vcpu) { - struct rb_node **rb = &result.rb_node; + struct rb_node **rb = &result->rb_node; struct rb_node *parent = NULL; struct kvm_event *p; @@ -552,13 +574,15 @@ static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, } rb_link_node(&event->rb, parent, rb); - rb_insert_color(&event->rb, &result); + rb_insert_color(&event->rb, result); } -static void update_total_count(struct kvm_event *event, int vcpu) +static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event) { - total_count += get_event_count(event, vcpu); - total_time += get_event_time(event, vcpu); + int vcpu = kvm->trace_vcpu; + + kvm->total_count += get_event_count(event, vcpu); + kvm->total_time += get_event_time(event, vcpu); } static bool event_is_valid(struct kvm_event *event, int vcpu) @@ -566,28 +590,30 @@ static bool event_is_valid(struct kvm_event *event, int vcpu) return !!get_event_count(event, vcpu); } -static void sort_result(int vcpu) +static void sort_result(struct perf_kvm *kvm) { unsigned int i; + int vcpu = kvm->trace_vcpu; struct kvm_event *event; for (i = 0; i < EVENTS_CACHE_SIZE; i++) - list_for_each_entry(event, &kvm_events_cache[i], hash_entry) + list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) if (event_is_valid(event, vcpu)) { - update_total_count(event, vcpu); - insert_to_result(event, compare, vcpu); + update_total_count(kvm, event); + insert_to_result(&kvm->result, event, + kvm->compare, vcpu); } } /* returns left most element of result, and erase it */ -static struct kvm_event *pop_from_result(void) +static struct kvm_event *pop_from_result(struct rb_root *result) { - struct rb_node *node = rb_first(&result); + struct rb_node *node = rb_first(result); if (!node) return NULL; - rb_erase(node, &result); + rb_erase(node, result); return container_of(node, struct kvm_event, rb); } @@ -601,14 +627,15 @@ static void print_vcpu_info(int vcpu) pr_info("VCPU %d:\n\n", vcpu); } -static void print_result(int vcpu) +static void print_result(struct perf_kvm *kvm) { char decode[20]; struct kvm_event *event; + int vcpu = kvm->trace_vcpu; pr_info("\n\n"); print_vcpu_info(vcpu); - pr_info("%20s ", events_ops->name); + pr_info("%20s ", kvm->events_ops->name); pr_info("%10s ", "Samples"); pr_info("%9s ", "Samples%"); @@ -616,33 +643,34 @@ static void print_result(int vcpu) pr_info("%16s ", "Avg time"); pr_info("\n\n"); - while ((event = pop_from_result())) { + while ((event = pop_from_result(&kvm->result))) { u64 ecount, etime; ecount = get_event_count(event, vcpu); etime = get_event_time(event, vcpu); - events_ops->decode_key(&event->key, decode); + kvm->events_ops->decode_key(kvm, &event->key, decode); pr_info("%20s ", decode); pr_info("%10llu ", (unsigned long long)ecount); - pr_info("%8.2f%% ", (double)ecount / total_count * 100); - pr_info("%8.2f%% ", (double)etime / total_time * 100); + pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); + pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, kvm_event_rel_stddev(vcpu, event)); pr_info("\n"); } pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", - (unsigned long long)total_count, total_time / 1e3); + (unsigned long long)kvm->total_count, kvm->total_time / 1e3); } -static int process_sample_event(struct perf_tool *tool __maybe_unused, +static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct machine *machine) { struct thread *thread = machine__findnew_thread(machine, sample->tid); + struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", @@ -650,18 +678,12 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, return -1; } - if (!handle_kvm_event(thread, evsel, sample)) + if (!handle_kvm_event(kvm, thread, evsel, sample)) return -1; return 0; } -static struct perf_tool eops = { - .sample = process_sample_event, - .comm = perf_event__process_comm, - .ordered_samples = true, -}; - static int get_cpu_isa(struct perf_session *session) { char *cpuid = session->header.env.cpuid; @@ -679,34 +701,43 @@ static int get_cpu_isa(struct perf_session *session) return isa; } -static const char *file_name; - -static int read_events(void) +static int read_events(struct perf_kvm *kvm) { - struct perf_session *kvm_session; int ret; - kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops); - if (!kvm_session) { + struct perf_tool eops = { + .sample = process_sample_event, + .comm = perf_event__process_comm, + .ordered_samples = true, + }; + + kvm->tool = eops; + kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false, + &kvm->tool); + if (!kvm->session) { pr_err("Initializing perf session failed\n"); return -EINVAL; } - if (!perf_session__has_traces(kvm_session, "kvm record")) + if (!perf_session__has_traces(kvm->session, "kvm record")) return -EINVAL; /* * Do not use 'isa' recorded in kvm_exit tracepoint since it is not * traced in the old kernel. */ - ret = get_cpu_isa(kvm_session); + ret = get_cpu_isa(kvm->session); if (ret < 0) return ret; - cpu_isa = ret; + if (ret == 1) { + kvm->exit_reasons = vmx_exit_reasons; + kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons); + kvm->exit_reasons_isa = "VMX"; + } - return perf_session__process_events(kvm_session, &eops); + return perf_session__process_events(kvm->session, &kvm->tool); } static bool verify_vcpu(int vcpu) @@ -719,28 +750,30 @@ static bool verify_vcpu(int vcpu) return true; } -static int kvm_events_report_vcpu(int vcpu) +static int kvm_events_report_vcpu(struct perf_kvm *kvm) { int ret = -EINVAL; + int vcpu = kvm->trace_vcpu; if (!verify_vcpu(vcpu)) goto exit; - if (!select_key()) + if (!select_key(kvm)) goto exit; - if (!register_kvm_events_ops()) + if (!register_kvm_events_ops(kvm)) goto exit; - init_kvm_event_record(); + init_kvm_event_record(kvm); setup_pager(); - ret = read_events(); + ret = read_events(kvm); if (ret) goto exit; - sort_result(vcpu); - print_result(vcpu); + sort_result(kvm); + print_result(kvm); + exit: return ret; } @@ -765,7 +798,7 @@ static const char * const record_args[] = { _p; \ }) -static int kvm_events_record(int argc, const char **argv) +static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv) { unsigned int rec_argc, i, j; const char **rec_argv; @@ -780,7 +813,7 @@ static int kvm_events_record(int argc, const char **argv) rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); - rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); + rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); for (j = 1; j < (unsigned int)argc; j++, i++) rec_argv[i] = argv[j]; @@ -788,24 +821,24 @@ static int kvm_events_record(int argc, const char **argv) return cmd_record(i, rec_argv, NULL); } -static const char * const kvm_events_report_usage[] = { - "perf kvm stat report [<options>]", - NULL -}; +static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv) +{ + const struct option kvm_events_report_options[] = { + OPT_STRING(0, "event", &kvm->report_event, "report event", + "event for reporting: vmexit, mmio, ioport"), + OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, + "vcpu id to report"), + OPT_STRING('k', "key", &kvm->sort_key, "sort-key", + "key for sorting: sample(sort by samples number)" + " time (sort by avg time)"), + OPT_END() + }; -static const struct option kvm_events_report_options[] = { - OPT_STRING(0, "event", &report_event, "report event", - "event for reporting: vmexit, mmio, ioport"), - OPT_INTEGER(0, "vcpu", &trace_vcpu, - "vcpu id to report"), - OPT_STRING('k', "key", &sort_key, "sort-key", - "key for sorting: sample(sort by samples number)" - " time (sort by avg time)"), - OPT_END() -}; + const char * const kvm_events_report_usage[] = { + "perf kvm stat report [<options>]", + NULL + }; -static int kvm_events_report(int argc, const char **argv) -{ symbol__init(); if (argc) { @@ -817,7 +850,7 @@ static int kvm_events_report(int argc, const char **argv) kvm_events_report_options); } - return kvm_events_report_vcpu(trace_vcpu); + return kvm_events_report_vcpu(kvm); } static void print_kvm_stat_usage(void) @@ -831,7 +864,7 @@ static void print_kvm_stat_usage(void) printf("\nOtherwise, it is the alias of 'perf stat':\n"); } -static int kvm_cmd_stat(int argc, const char **argv) +static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv) { if (argc == 1) { print_kvm_stat_usage(); @@ -839,44 +872,16 @@ static int kvm_cmd_stat(int argc, const char **argv) } if (!strncmp(argv[1], "rec", 3)) - return kvm_events_record(argc - 1, argv + 1); + return kvm_events_record(kvm, argc - 1, argv + 1); if (!strncmp(argv[1], "rep", 3)) - return kvm_events_report(argc - 1 , argv + 1); + return kvm_events_report(kvm, argc - 1 , argv + 1); perf_stat: return cmd_stat(argc, argv, NULL); } -static char name_buffer[256]; - -static const char * const kvm_usage[] = { - "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", - NULL -}; - -static const struct option kvm_options[] = { - OPT_STRING('i', "input", &file_name, "file", - "Input file name"), - OPT_STRING('o', "output", &file_name, "file", - "Output file name"), - OPT_BOOLEAN(0, "guest", &perf_guest, - "Collect guest os data"), - OPT_BOOLEAN(0, "host", &perf_host, - "Collect host os data"), - OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", - "guest mount directory under which every guest os" - " instance has a subdir"), - OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, - "file", "file saving guest os vmlinux"), - OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, - "file", "file saving guest os /proc/kallsyms"), - OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, - "file", "file saving guest os /proc/modules"), - OPT_END() -}; - -static int __cmd_record(int argc, const char **argv) +static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv) { int rec_argc, i = 0, j; const char **rec_argv; @@ -885,7 +890,7 @@ static int __cmd_record(int argc, const char **argv) rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("record"); rec_argv[i++] = strdup("-o"); - rec_argv[i++] = strdup(file_name); + rec_argv[i++] = strdup(kvm->file_name); for (j = 1; j < argc; j++, i++) rec_argv[i] = argv[j]; @@ -894,7 +899,7 @@ static int __cmd_record(int argc, const char **argv) return cmd_record(i, rec_argv, NULL); } -static int __cmd_report(int argc, const char **argv) +static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv) { int rec_argc, i = 0, j; const char **rec_argv; @@ -903,7 +908,7 @@ static int __cmd_report(int argc, const char **argv) rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("report"); rec_argv[i++] = strdup("-i"); - rec_argv[i++] = strdup(file_name); + rec_argv[i++] = strdup(kvm->file_name); for (j = 1; j < argc; j++, i++) rec_argv[i] = argv[j]; @@ -912,7 +917,7 @@ static int __cmd_report(int argc, const char **argv) return cmd_report(i, rec_argv, NULL); } -static int __cmd_buildid_list(int argc, const char **argv) +static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv) { int rec_argc, i = 0, j; const char **rec_argv; @@ -921,7 +926,7 @@ static int __cmd_buildid_list(int argc, const char **argv) rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("buildid-list"); rec_argv[i++] = strdup("-i"); - rec_argv[i++] = strdup(file_name); + rec_argv[i++] = strdup(kvm->file_name); for (j = 1; j < argc; j++, i++) rec_argv[i] = argv[j]; @@ -932,6 +937,43 @@ static int __cmd_buildid_list(int argc, const char **argv) int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) { + struct perf_kvm kvm = { + .trace_vcpu = -1, + .report_event = "vmexit", + .sort_key = "sample", + + .exit_reasons = svm_exit_reasons, + .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons), + .exit_reasons_isa = "SVM", + }; + + const struct option kvm_options[] = { + OPT_STRING('i', "input", &kvm.file_name, "file", + "Input file name"), + OPT_STRING('o', "output", &kvm.file_name, "file", + "Output file name"), + OPT_BOOLEAN(0, "guest", &perf_guest, + "Collect guest os data"), + OPT_BOOLEAN(0, "host", &perf_host, + "Collect host os data"), + OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", + "guest mount directory under which every guest os" + " instance has a subdir"), + OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, + "file", "file saving guest os vmlinux"), + OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, + "file", "file saving guest os /proc/kallsyms"), + OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, + "file", "file saving guest os /proc/modules"), + OPT_END() + }; + + + const char * const kvm_usage[] = { + "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", + NULL + }; + perf_host = 0; perf_guest = 1; @@ -943,28 +985,32 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) if (!perf_host) perf_guest = 1; - if (!file_name) { + if (!kvm.file_name) { if (perf_host && !perf_guest) - sprintf(name_buffer, "perf.data.host"); + kvm.file_name = strdup("perf.data.host"); else if (!perf_host && perf_guest) - sprintf(name_buffer, "perf.data.guest"); + kvm.file_name = strdup("perf.data.guest"); else - sprintf(name_buffer, "perf.data.kvm"); - file_name = name_buffer; + kvm.file_name = strdup("perf.data.kvm"); + + if (!kvm.file_name) { + pr_err("Failed to allocate memory for filename\n"); + return -ENOMEM; + } } if (!strncmp(argv[0], "rec", 3)) - return __cmd_record(argc, argv); + return __cmd_record(&kvm, argc, argv); else if (!strncmp(argv[0], "rep", 3)) - return __cmd_report(argc, argv); + return __cmd_report(&kvm, argc, argv); else if (!strncmp(argv[0], "diff", 4)) return cmd_diff(argc, argv, NULL); else if (!strncmp(argv[0], "top", 3)) return cmd_top(argc, argv, NULL); else if (!strncmp(argv[0], "buildid-list", 12)) - return __cmd_buildid_list(argc, argv); + return __cmd_buildid_list(&kvm, argc, argv); else if (!strncmp(argv[0], "stat", 4)) - return kvm_cmd_stat(argc, argv); + return kvm_cmd_stat(&kvm, argc, argv); else usage_with_options(kvm_usage, kvm_options); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 7d6e09949880..6f5f328157aa 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -823,12 +823,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, return 0; } -static struct perf_tool eops = { - .sample = process_sample_event, - .comm = perf_event__process_comm, - .ordered_samples = true, -}; - static const struct perf_evsel_str_handler lock_tracepoints[] = { { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ @@ -838,6 +832,11 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = { static int read_events(void) { + struct perf_tool eops = { + .sample = process_sample_event, + .comm = perf_event__process_comm, + .ordered_samples = true, + }; session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); if (!session) { pr_err("Initializing perf session failed\n"); @@ -878,53 +877,11 @@ static int __cmd_report(void) return 0; } -static const char * const report_usage[] = { - "perf lock report [<options>]", - NULL -}; - -static const struct option report_options[] = { - OPT_STRING('k', "key", &sort_key, "acquired", - "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), - /* TODO: type */ - OPT_END() -}; - -static const char * const info_usage[] = { - "perf lock info [<options>]", - NULL -}; - -static const struct option info_options[] = { - OPT_BOOLEAN('t', "threads", &info_threads, - "dump thread list in perf.data"), - OPT_BOOLEAN('m', "map", &info_map, - "map of lock instances (address:name table)"), - OPT_END() -}; - -static const char * const lock_usage[] = { - "perf lock [<options>] {record|report|script|info}", - NULL -}; - -static const struct option lock_options[] = { - OPT_STRING('i', "input", &input_name, "file", "input file name"), - OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), - OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_END() -}; - -static const char *record_args[] = { - "record", - "-R", - "-f", - "-m", "1024", - "-c", "1", -}; - static int __cmd_record(int argc, const char **argv) { + const char *record_args[] = { + "record", "-R", "-f", "-m", "1024", "-c", "1", + }; unsigned int rec_argc, i, j; const char **rec_argv; @@ -963,6 +920,37 @@ static int __cmd_record(int argc, const char **argv) int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) { + const struct option info_options[] = { + OPT_BOOLEAN('t', "threads", &info_threads, + "dump thread list in perf.data"), + OPT_BOOLEAN('m', "map", &info_map, + "map of lock instances (address:name table)"), + OPT_END() + }; + const struct option lock_options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), + OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), + OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), + OPT_END() + }; + const struct option report_options[] = { + OPT_STRING('k', "key", &sort_key, "acquired", + "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), + /* TODO: type */ + OPT_END() + }; + const char * const info_usage[] = { + "perf lock info [<options>]", + NULL + }; + const char * const lock_usage[] = { + "perf lock [<options>] {record|report|script|info}", + NULL + }; + const char * const report_usage[] = { + "perf lock report [<options>]", + NULL + }; unsigned int i; int rc = 0; diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 118aa8946573..de38a034b129 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -250,19 +250,20 @@ static int opt_set_filter(const struct option *opt __maybe_unused, return 0; } -static const char * const probe_usage[] = { - "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", - "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", - "perf probe [<options>] --del '[GROUP:]EVENT' ...", - "perf probe --list", +int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) +{ + const char * const probe_usage[] = { + "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", + "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", + "perf probe [<options>] --del '[GROUP:]EVENT' ...", + "perf probe --list", #ifdef DWARF_SUPPORT - "perf probe [<options>] --line 'LINEDESC'", - "perf probe [<options>] --vars 'PROBEPOINT'", + "perf probe [<options>] --line 'LINEDESC'", + "perf probe [<options>] --vars 'PROBEPOINT'", #endif - NULL + NULL }; - -static const struct option options[] = { + const struct option options[] = { OPT_INCR('v', "verbose", &verbose, "be more verbose (show parsed arguments, etc)"), OPT_BOOLEAN('l', "list", ¶ms.list_events, @@ -325,10 +326,7 @@ static const struct option options[] = { OPT_CALLBACK('x', "exec", NULL, "executable|path", "target executable name or path", opt_set_target), OPT_END() -}; - -int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) -{ + }; int ret; argc = parse_options(argc, argv, options, probe_usage, diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f14cb5fdb91f..e9231659754d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -31,15 +31,6 @@ #include <sched.h> #include <sys/mman.h> -#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " - -#ifdef NO_LIBUNWIND_SUPPORT -static char callchain_help[] = CALLCHAIN_HELP "[fp]"; -#else -static unsigned long default_stack_dump_size = 8192; -static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; -#endif - enum write_mode_t { WRITE_FORCE, WRITE_APPEND @@ -800,7 +791,7 @@ error: return ret; } -#ifndef NO_LIBUNWIND_SUPPORT +#ifdef LIBUNWIND_SUPPORT static int get_stack_size(char *str, unsigned long *_size) { char *endptr; @@ -826,7 +817,7 @@ static int get_stack_size(char *str, unsigned long *_size) max_size, str); return -1; } -#endif /* !NO_LIBUNWIND_SUPPORT */ +#endif /* LIBUNWIND_SUPPORT */ static int parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, @@ -865,9 +856,11 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, "needed for -g fp\n"); break; -#ifndef NO_LIBUNWIND_SUPPORT +#ifdef LIBUNWIND_SUPPORT /* Dwarf style */ } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { + const unsigned long default_stack_dump_size = 8192; + ret = 0; rec->opts.call_graph = CALLCHAIN_DWARF; rec->opts.stack_dump_size = default_stack_dump_size; @@ -883,7 +876,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, if (!ret) pr_debug("callchain: stack dump size %d\n", rec->opts.stack_dump_size); -#endif /* !NO_LIBUNWIND_SUPPORT */ +#endif /* LIBUNWIND_SUPPORT */ } else { pr_err("callchain: Unknown -g option " "value: %s\n", arg); @@ -930,6 +923,14 @@ static struct perf_record record = { .file_new = true, }; +#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " + +#ifdef LIBUNWIND_SUPPORT +static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; +#else +static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; +#endif + /* * XXX Will stay a global variable till we fix builtin-script.c to stop messing * with it and switch to use the library functions in perf_evlist that came diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1da243dfbc3e..a61725d89d3e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, const char *evname = perf_evsel__name(pos); hists__fprintf_nr_sample_events(hists, evname, stdout); - hists__fprintf(hists, NULL, false, true, 0, 0, stdout); + hists__fprintf(hists, true, 0, 0, stdout); fprintf(stdout, "\n\n"); } @@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) setup_browser(true); else { use_browser = 0; - perf_hpp__init(false, false); + perf_hpp__init(); } setup_sorting(report_usage, options); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 9b9e32eaa805..3488ead3b60c 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1426,7 +1426,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, sample->pid); + struct thread *thread = machine__findnew_thread(machine, sample->tid); int err = 0; if (thread == NULL) { diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 1be843aa1546..fb9625083a2e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -24,7 +24,6 @@ static u64 last_timestamp; static u64 nr_unordered; extern const struct option record_options[]; static bool no_callchain; -static bool show_full_info; static bool system_wide; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); @@ -473,8 +472,6 @@ static int cleanup_scripting(void) return scripting_ops->stop_script(); } -static const char *input_name; - static int process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, @@ -1156,20 +1153,40 @@ out: return n_args; } -static const char * const script_usage[] = { - "perf script [<options>]", - "perf script [<options>] record <script> [<record-options>] <command>", - "perf script [<options>] report <script> [script-args]", - "perf script [<options>] <script> [<record-options>] <command>", - "perf script [<options>] <top-script> [script-args]", - NULL -}; +static int have_cmd(int argc, const char **argv) +{ + char **__argv = malloc(sizeof(const char *) * argc); + + if (!__argv) { + pr_err("malloc failed\n"); + return -1; + } + + memcpy(__argv, argv, sizeof(const char *) * argc); + argc = parse_options(argc, (const char **)__argv, record_options, + NULL, PARSE_OPT_STOP_AT_NON_OPTION); + free(__argv); -static const struct option options[] = { + system_wide = (argc == 0); + + return 0; +} + +int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) +{ + bool show_full_info = false; + const char *input_name = NULL; + char *rec_script_path = NULL; + char *rep_script_path = NULL; + struct perf_session *session; + char *script_path = NULL; + const char **__argv; + int i, j, err; + const struct option options[] = { OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_INCR('v', "verbose", &verbose, - "be more verbose (show symbol address, etc)"), + "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('L', "Latency", &latency_format, "show latency attributes (irqs/preemption disabled, etc)"), OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", @@ -1179,8 +1196,7 @@ static const struct option options[] = { parse_scriptname), OPT_STRING('g', "gen-script", &generate_script_lang, "lang", "generate perf-script.xx script in specified language"), - OPT_STRING('i', "input", &input_name, "file", - "input file name"), + OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_BOOLEAN('d', "debug-mode", &debug_mode, "do various checks like samples ordering and lost events"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, @@ -1195,10 +1211,9 @@ static const struct option options[] = { "comma separated output fields prepend with 'type:'. " "Valid types: hw,sw,trace,raw. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," - "addr,symoff", - parse_output_fields), + "addr,symoff", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, - "system-wide collection from all CPUs"), + "system-wide collection from all CPUs"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", "only consider these symbols"), OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), @@ -1208,37 +1223,16 @@ static const struct option options[] = { "display extended information from perf.data file"), OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, "Show the path of [kernel.kallsyms]"), - OPT_END() -}; - -static int have_cmd(int argc, const char **argv) -{ - char **__argv = malloc(sizeof(const char *) * argc); - - if (!__argv) { - pr_err("malloc failed\n"); - return -1; - } - - memcpy(__argv, argv, sizeof(const char *) * argc); - argc = parse_options(argc, (const char **)__argv, record_options, - NULL, PARSE_OPT_STOP_AT_NON_OPTION); - free(__argv); - - system_wide = (argc == 0); - - return 0; -} - -int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) -{ - char *rec_script_path = NULL; - char *rep_script_path = NULL; - struct perf_session *session; - char *script_path = NULL; - const char **__argv; - int i, j, err; + }; + const char * const script_usage[] = { + "perf script [<options>]", + "perf script [<options>] record <script> [<record-options>] <command>", + "perf script [<options>] report <script> [script-args]", + "perf script [<options>] <script> [<record-options>] <command>", + "perf script [<options>] <top-script> [script-args]", + NULL + }; setup_scripting(); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e8cd4d81b06e..93b9011fa3e2 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -64,122 +64,12 @@ #define CNTR_NOT_SUPPORTED "<not supported>" #define CNTR_NOT_COUNTED "<not counted>" -static struct perf_event_attr default_attrs[] = { - - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, - - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, - -}; - -/* - * Detailed stats (-d), covering the L1 and last level data caches: - */ -static struct perf_event_attr detailed_attrs[] = { - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_LL << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_LL << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, -}; - -/* - * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: - */ -static struct perf_event_attr very_detailed_attrs[] = { - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1I << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1I << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_DTLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_DTLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_ITLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_ITLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - -}; - -/* - * Very, very detailed stats (-d -d -d), adding prefetch events: - */ -static struct perf_event_attr very_very_detailed_attrs[] = { - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, -}; - - - static struct perf_evlist *evsel_list; static struct perf_target target = { .uid = UINT_MAX, }; -static int run_idx = 0; static int run_count = 1; static bool no_inherit = false; static bool scale = true; @@ -187,15 +77,12 @@ static bool no_aggr = false; static pid_t child_pid = -1; static bool null_run = false; static int detailed_run = 0; -static bool sync_run = false; static bool big_num = true; static int big_num_opt = -1; static const char *csv_sep = NULL; static bool csv_output = false; static bool group = false; -static const char *output_name = NULL; static FILE *output = NULL; -static int output_fd; static volatile int done = 0; @@ -1028,11 +915,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -static const char * const stat_usage[] = { - "perf stat [<options>] [<command>]", - NULL -}; - static int stat__set_big_num(const struct option *opt __maybe_unused, const char *s __maybe_unused, int unset) { @@ -1040,62 +922,119 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, return 0; } -static bool append_file; - -static const struct option options[] = { - OPT_CALLBACK('e', "event", &evsel_list, "event", - "event selector. use 'perf list' to list available events", - parse_events_option), - OPT_CALLBACK(0, "filter", &evsel_list, "filter", - "event filter", parse_filter), - OPT_BOOLEAN('i', "no-inherit", &no_inherit, - "child tasks do not inherit counters"), - OPT_STRING('p', "pid", &target.pid, "pid", - "stat events on existing process id"), - OPT_STRING('t', "tid", &target.tid, "tid", - "stat events on existing thread id"), - OPT_BOOLEAN('a', "all-cpus", &target.system_wide, - "system-wide collection from all CPUs"), - OPT_BOOLEAN('g', "group", &group, - "put the counters into a counter group"), - OPT_BOOLEAN('c', "scale", &scale, - "scale/normalize counters"), - OPT_INCR('v', "verbose", &verbose, - "be more verbose (show counter open errors, etc)"), - OPT_INTEGER('r', "repeat", &run_count, - "repeat command and print average + stddev (max: 100)"), - OPT_BOOLEAN('n', "null", &null_run, - "null run - dont start any counters"), - OPT_INCR('d', "detailed", &detailed_run, - "detailed run - start a lot of events"), - OPT_BOOLEAN('S', "sync", &sync_run, - "call sync() before starting a run"), - OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, - "print large numbers with thousands\' separators", - stat__set_big_num), - OPT_STRING('C', "cpu", &target.cpu_list, "cpu", - "list of cpus to monitor in system-wide"), - OPT_BOOLEAN('A', "no-aggr", &no_aggr, - "disable CPU count aggregation"), - OPT_STRING('x', "field-separator", &csv_sep, "separator", - "print counts with custom separator"), - OPT_CALLBACK('G', "cgroup", &evsel_list, "name", - "monitor event in cgroup name only", - parse_cgroups), - OPT_STRING('o', "output", &output_name, "file", - "output file name"), - OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), - OPT_INTEGER(0, "log-fd", &output_fd, - "log output to fd, instead of stderr"), - OPT_END() -}; - /* * Add default attributes, if there were no attributes specified or * if -d/--detailed, -d -d or -d -d -d is used: */ static int add_default_attributes(void) { + struct perf_event_attr default_attrs[] = { + + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, + + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, + +}; + +/* + * Detailed stats (-d), covering the L1 and last level data caches: + */ + struct perf_event_attr detailed_attrs[] = { + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_LL << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_LL << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, +}; + +/* + * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: + */ + struct perf_event_attr very_detailed_attrs[] = { + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1I << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1I << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_DTLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_DTLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_ITLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_ITLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + +}; + +/* + * Very, very detailed stats (-d -d -d), adding prefetch events: + */ + struct perf_event_attr very_very_detailed_attrs[] = { + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, +}; + /* Set attrs if no event is selected and !null_run: */ if (null_run) return 0; @@ -1130,8 +1069,59 @@ static int add_default_attributes(void) int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) { + bool append_file = false, + sync_run = false; + int output_fd = 0; + const char *output_name = NULL; + const struct option options[] = { + OPT_CALLBACK('e', "event", &evsel_list, "event", + "event selector. use 'perf list' to list available events", + parse_events_option), + OPT_CALLBACK(0, "filter", &evsel_list, "filter", + "event filter", parse_filter), + OPT_BOOLEAN('i', "no-inherit", &no_inherit, + "child tasks do not inherit counters"), + OPT_STRING('p', "pid", &target.pid, "pid", + "stat events on existing process id"), + OPT_STRING('t', "tid", &target.tid, "tid", + "stat events on existing thread id"), + OPT_BOOLEAN('a', "all-cpus", &target.system_wide, + "system-wide collection from all CPUs"), + OPT_BOOLEAN('g', "group", &group, + "put the counters into a counter group"), + OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"), + OPT_INCR('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), + OPT_INTEGER('r', "repeat", &run_count, + "repeat command and print average + stddev (max: 100)"), + OPT_BOOLEAN('n', "null", &null_run, + "null run - dont start any counters"), + OPT_INCR('d', "detailed", &detailed_run, + "detailed run - start a lot of events"), + OPT_BOOLEAN('S', "sync", &sync_run, + "call sync() before starting a run"), + OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, + "print large numbers with thousands\' separators", + stat__set_big_num), + OPT_STRING('C', "cpu", &target.cpu_list, "cpu", + "list of cpus to monitor in system-wide"), + OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), + OPT_STRING('x', "field-separator", &csv_sep, "separator", + "print counts with custom separator"), + OPT_CALLBACK('G', "cgroup", &evsel_list, "name", + "monitor event in cgroup name only", parse_cgroups), + OPT_STRING('o', "output", &output_name, "file", "output file name"), + OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), + OPT_INTEGER(0, "log-fd", &output_fd, + "log output to fd, instead of stderr"), + OPT_END() + }; + const char * const stat_usage[] = { + "perf stat [<options>] [<command>]", + NULL + }; struct perf_evsel *pos; - int status = -ENOMEM; + int status = -ENOMEM, run_idx; const char *mode; setlocale(LC_ALL, ""); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index b1a8a3b841cc..f251b613b2f3 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -38,9 +38,6 @@ #define PWR_EVENT_EXIT -1 -static const char *input_name; -static const char *output_name = "output.svg"; - static unsigned int numcpus; static u64 min_freq; /* Lowest CPU frequency seen */ static u64 max_freq; /* Highest CPU frequency seen */ @@ -968,16 +965,15 @@ static void write_svg_file(const char *filename) svg_close(); } -static struct perf_tool perf_timechart = { - .comm = process_comm_event, - .fork = process_fork_event, - .exit = process_exit_event, - .sample = process_sample_event, - .ordered_samples = true, -}; - -static int __cmd_timechart(void) +static int __cmd_timechart(const char *input_name, const char *output_name) { + struct perf_tool perf_timechart = { + .comm = process_comm_event, + .fork = process_fork_event, + .exit = process_exit_event, + .sample = process_sample_event, + .ordered_samples = true, + }; struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_timechart); int ret = -EINVAL; @@ -1005,40 +1001,25 @@ out_delete: return ret; } -static const char * const timechart_usage[] = { - "perf timechart [<options>] {record}", - NULL -}; - -#ifdef SUPPORT_OLD_POWER_EVENTS -static const char * const record_old_args[] = { - "record", - "-a", - "-R", - "-f", - "-c", "1", - "-e", "power:power_start", - "-e", "power:power_end", - "-e", "power:power_frequency", - "-e", "sched:sched_wakeup", - "-e", "sched:sched_switch", -}; -#endif - -static const char * const record_new_args[] = { - "record", - "-a", - "-R", - "-f", - "-c", "1", - "-e", "power:cpu_frequency", - "-e", "power:cpu_idle", - "-e", "sched:sched_wakeup", - "-e", "sched:sched_switch", -}; - static int __cmd_record(int argc, const char **argv) { +#ifdef SUPPORT_OLD_POWER_EVENTS + const char * const record_old_args[] = { + "record", "-a", "-R", "-f", "-c", "1", + "-e", "power:power_start", + "-e", "power:power_end", + "-e", "power:power_frequency", + "-e", "sched:sched_wakeup", + "-e", "sched:sched_switch", + }; +#endif + const char * const record_new_args[] = { + "record", "-a", "-R", "-f", "-c", "1", + "-e", "power:cpu_frequency", + "-e", "power:cpu_idle", + "-e", "sched:sched_wakeup", + "-e", "sched:sched_switch", + }; unsigned int rec_argc, i, j; const char **rec_argv; const char * const *record_args = record_new_args; @@ -1077,27 +1058,28 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, return 0; } -static const struct option options[] = { - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_STRING('o', "output", &output_name, "file", - "output file name"), - OPT_INTEGER('w', "width", &svg_page_width, - "page width"), - OPT_BOOLEAN('P', "power-only", &power_only, - "output power data only"), +int cmd_timechart(int argc, const char **argv, + const char *prefix __maybe_unused) +{ + const char *input_name; + const char *output_name = "output.svg"; + const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), + OPT_STRING('o', "output", &output_name, "file", "output file name"), + OPT_INTEGER('w', "width", &svg_page_width, "page width"), + OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), OPT_CALLBACK('p', "process", NULL, "process", "process selector. Pass a pid or process name.", parse_process), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), OPT_END() -}; - + }; + const char * const timechart_usage[] = { + "perf timechart [<options>] {record}", + NULL + }; -int cmd_timechart(int argc, const char **argv, - const char *prefix __maybe_unused) -{ argc = parse_options(argc, argv, options, timechart_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -1110,5 +1092,5 @@ int cmd_timechart(int argc, const char **argv, setup_pager(); - return __cmd_timechart(); + return __cmd_timechart(input_name, output_name); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e434a16bb5ac..ff6db8086805 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top) hists__output_recalc_col_len(&top->sym_evsel->hists, top->winsize.ws_row - 3); putchar('\n'); - hists__fprintf(&top->sym_evsel->hists, NULL, false, false, + hists__fprintf(&top->sym_evsel->hists, false, top->winsize.ws_row - 4 - printed, win_width, stdout); } @@ -1159,11 +1159,6 @@ setup: return 0; } -static const char * const top_usage[] = { - "perf top [<options>]", - NULL -}; - int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) { struct perf_evsel *pos; @@ -1250,6 +1245,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), OPT_END() }; + const char * const top_usage[] = { + "perf top [<options>]", + NULL + }; top.evlist = perf_evlist__new(NULL, NULL); if (top.evlist == NULL) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8f113dab8bf1..dec8ced61fb0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -114,10 +114,85 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL return printed; } +typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, + struct perf_sample *sample); + +static struct syscall *trace__syscall_info(struct trace *trace, + struct perf_evsel *evsel, + struct perf_sample *sample) +{ + int id = perf_evsel__intval(evsel, sample, "id"); + + if (id < 0) { + printf("Invalid syscall %d id, skipping...\n", id); + return NULL; + } + + if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && + trace__read_syscall_info(trace, id)) + goto out_cant_read; + + if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) + goto out_cant_read; + + return &trace->syscalls.table[id]; + +out_cant_read: + printf("Problems reading syscall %d information\n", id); + return NULL; +} + +static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, + struct perf_sample *sample) +{ + void *args; + struct syscall *sc = trace__syscall_info(trace, evsel, sample); + + if (sc == NULL) + return -1; + + args = perf_evsel__rawptr(evsel, sample, "args"); + if (args == NULL) { + printf("Problems reading syscall arguments\n"); + return -1; + } + + printf("%s(", sc->name); + syscall__fprintf_args(sc, args, stdout); + + return 0; +} + +static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, + struct perf_sample *sample) +{ + int ret; + struct syscall *sc = trace__syscall_info(trace, evsel, sample); + + if (sc == NULL) + return -1; + + ret = perf_evsel__intval(evsel, sample, "ret"); + + if (ret < 0 && sc->fmt && sc->fmt->errmsg) { + char bf[256]; + const char *emsg = strerror_r(-ret, bf, sizeof(bf)), + *e = audit_errno_to_name(-ret); + + printf(") = -1 %s %s", e, emsg); + } else if (ret == 0 && sc->fmt && sc->fmt->timeout) + printf(") = 0 Timeout"); + else + printf(") = %d", ret); + + putchar('\n'); + return 0; +} + static int trace__run(struct trace *trace) { struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); - struct perf_evsel *evsel, *evsel_enter, *evsel_exit; + struct perf_evsel *evsel; int err = -1, i, nr_events = 0, before; if (evlist == NULL) { @@ -125,22 +200,12 @@ static int trace__run(struct trace *trace) goto out; } - evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0); - if (evsel_enter == NULL) { - printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n"); - goto out_delete_evlist; - } - - perf_evlist__add(evlist, evsel_enter); - - evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1); - if (evsel_exit == NULL) { - printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n"); + if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || + perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { + printf("Couldn't read the raw_syscalls tracepoints information!\n"); goto out_delete_evlist; } - perf_evlist__add(evlist, evsel_exit); - err = perf_evlist__create_maps(evlist, &trace->opts.target); if (err < 0) { printf("Problems parsing the target to trace, check your options!\n"); @@ -170,9 +235,8 @@ again: while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { const u32 type = event->header.type; - struct syscall *sc; + tracepoint_handler handler; struct perf_sample sample; - int id; ++nr_events; @@ -200,45 +264,11 @@ again: continue; } - id = perf_evsel__intval(evsel, &sample, "id"); - if (id < 0) { - printf("Invalid syscall %d id, skipping...\n", id); - continue; - } - - if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && - trace__read_syscall_info(trace, id)) - continue; - - if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) - continue; - - sc = &trace->syscalls.table[id]; - if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) printf("%d ", sample.tid); - if (evsel == evsel_enter) { - void *args = perf_evsel__rawptr(evsel, &sample, "args"); - - printf("%s(", sc->name); - syscall__fprintf_args(sc, args, stdout); - } else if (evsel == evsel_exit) { - int ret = perf_evsel__intval(evsel, &sample, "ret"); - - if (ret < 0 && sc->fmt && sc->fmt->errmsg) { - char bf[256]; - const char *emsg = strerror_r(-ret, bf, sizeof(bf)), - *e = audit_errno_to_name(-ret); - - printf(") = -1 %s %s", e, emsg); - } else if (ret == 0 && sc->fmt && sc->fmt->timeout) - printf(") = 0 Timeout"); - else - printf(") = %d", ret); - - putchar('\n'); - } + handler = evsel->handler.func; + handler(trace, evsel, &sample); } } diff --git a/tools/perf/perf.c b/tools/perf/perf.c index fc2f770e3027..6d50eb0b4251 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -48,14 +48,14 @@ static struct cmd_struct commands[] = { { "version", cmd_version, 0 }, { "script", cmd_script, 0 }, { "sched", cmd_sched, 0 }, -#ifndef NO_LIBELF_SUPPORT +#ifdef LIBELF_SUPPORT { "probe", cmd_probe, 0 }, #endif { "kmem", cmd_kmem, 0 }, { "lock", cmd_lock, 0 }, { "kvm", cmd_kvm, 0 }, { "test", cmd_test, 0 }, -#ifndef NO_LIBAUDIT_SUPPORT +#ifdef LIBAUDIT_SUPPORT { "trace", cmd_trace, 0 }, #endif { "inject", cmd_inject, 0 }, diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a21f40bebbac..0568536ecf67 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -569,7 +569,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser, static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - double percent = 100.0 * he->_field / hpp->total_period; \ + struct hists *hists = he->hists; \ + double percent = 100.0 * he->stat._field / hists->stats.total_period; \ *(double *)hpp->ptr = percent; \ return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ } @@ -584,7 +585,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) void hist_browser__init_hpp(void) { - perf_hpp__init(false, false); + perf_hpp__init(); perf_hpp__format[PERF_HPP__OVERHEAD].color = hist_browser__hpp_color_overhead; @@ -624,7 +625,6 @@ static int hist_browser__show_entry(struct hist_browser *browser, struct perf_hpp hpp = { .buf = s, .size = sizeof(s), - .total_period = browser->hists->stats.total_period, }; ui_browser__gotorc(&browser->b, row, 0); @@ -982,7 +982,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, folded_sign = hist_entry__folded(he); hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); - percent = (he->period * 100.0) / browser->hists->stats.total_period; + percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; if (symbol_conf.use_callchain) printed += fprintf(fp, "%c ", folded_sign); @@ -990,10 +990,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, printed += fprintf(fp, " %5.2f%%", percent); if (symbol_conf.show_nr_samples) - printed += fprintf(fp, " %11u", he->nr_events); + printed += fprintf(fp, " %11u", he->stat.nr_events); if (symbol_conf.show_total_period) - printed += fprintf(fp, " %12" PRIu64, he->period); + printed += fprintf(fp, " %12" PRIu64, he->stat.period); printed += fprintf(fp, "%s\n", rtrim(s)); diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 7ff99ec1d95e..4125c6284114 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c @@ -49,7 +49,8 @@ static const char *perf_gtk__get_percent_color(double percent) static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - double percent = 100.0 * he->_field / hpp->total_period; \ + struct hists *hists = he->hists; \ + double percent = 100.0 * he->stat._field / hists->stats.total_period; \ const char *markup; \ int ret = 0; \ \ @@ -73,7 +74,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) void perf_gtk__init_hpp(void) { - perf_hpp__init(false, false); + perf_hpp__init(); perf_hpp__format[PERF_HPP__OVERHEAD].color = perf_gtk__hpp_color_overhead; @@ -102,7 +103,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) struct perf_hpp hpp = { .buf = s, .size = sizeof(s), - .total_period = hists->stats.total_period, }; nr_cols = 0; diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index 8aada5b3c04c..ccb046aac98b 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -116,7 +116,7 @@ struct perf_error_ops perf_gtk_eops = { * FIXME: Functions below should be implemented properly. * For now, just add stubs for NO_NEWT=1 build. */ -#ifdef NO_NEWT_SUPPORT +#ifndef NEWT_SUPPORT void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused, const char *title __maybe_unused) { diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index 2b667ee454c3..baa28a4d16b9 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h @@ -23,25 +23,25 @@ void ui_helpline__puts(const char *msg); extern char ui_helpline__current[512]; -#ifdef NO_NEWT_SUPPORT +#ifdef NEWT_SUPPORT +extern char ui_helpline__last_msg[]; +int ui_helpline__show_help(const char *format, va_list ap); +#else static inline int ui_helpline__show_help(const char *format __maybe_unused, va_list ap __maybe_unused) { return 0; } -#else -extern char ui_helpline__last_msg[]; -int ui_helpline__show_help(const char *format, va_list ap); -#endif /* NO_NEWT_SUPPORT */ +#endif /* NEWT_SUPPORT */ -#ifdef NO_GTK2_SUPPORT +#ifdef GTK2_SUPPORT +int perf_gtk__show_helpline(const char *format, va_list ap); +#else static inline int perf_gtk__show_helpline(const char *format __maybe_unused, va_list ap __maybe_unused) { return 0; } -#else -int perf_gtk__show_helpline(const char *format, va_list ap); -#endif /* NO_GTK2_SUPPORT */ +#endif /* GTK2_SUPPORT */ #endif /* _PERF_UI_HELPLINE_H_ */ diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index e3f8cd46e7d7..f5a1e4f65263 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -8,9 +8,7 @@ /* hist period print (hpp) functions */ static int hpp__header_overhead(struct perf_hpp *hpp) { - const char *fmt = hpp->ptr ? "Baseline" : "Overhead"; - - return scnprintf(hpp->buf, hpp->size, fmt); + return scnprintf(hpp->buf, hpp->size, "Overhead"); } static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) @@ -20,38 +18,18 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period / hpp->total_period; - - if (hpp->ptr) { - struct hists *old_hists = hpp->ptr; - u64 total_period = old_hists->stats.total_period; - u64 base_period = he->pair ? he->pair->period : 0; - - if (total_period) - percent = 100.0 * base_period / total_period; - else - percent = 0.0; - } + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period / hists->stats.total_period; return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); } static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period / hists->stats.total_period; const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; - if (hpp->ptr) { - struct hists *old_hists = hpp->ptr; - u64 total_period = old_hists->stats.total_period; - u64 base_period = he->pair ? he->pair->period : 0; - - if (total_period) - percent = 100.0 * base_period / total_period; - else - percent = 0.0; - } - return scnprintf(hpp->buf, hpp->size, fmt, percent); } @@ -69,13 +47,16 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_sys / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; + return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); } static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_sys / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; return scnprintf(hpp->buf, hpp->size, fmt, percent); @@ -95,13 +76,16 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_us / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_us / hists->stats.total_period; + return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); } static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_us / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_us / hists->stats.total_period; const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; return scnprintf(hpp->buf, hpp->size, fmt, percent); @@ -120,14 +104,17 @@ static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_guest_sys / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; + return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); } static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_guest_sys / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; return scnprintf(hpp->buf, hpp->size, fmt, percent); @@ -146,19 +133,63 @@ static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_guest_us / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; + return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); } static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, struct hist_entry *he) { - double percent = 100.0 * he->period_guest_us / hpp->total_period; + struct hists *hists = he->hists; + double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; return scnprintf(hpp->buf, hpp->size, fmt, percent); } +static int hpp__header_baseline(struct perf_hpp *hpp) +{ + return scnprintf(hpp->buf, hpp->size, "Baseline"); +} + +static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) +{ + return 8; +} + +static double baseline_percent(struct hist_entry *he) +{ + struct hist_entry *pair = he->pair; + struct hists *pair_hists = pair ? pair->hists : NULL; + double percent = 0.0; + + if (pair) { + u64 total_period = pair_hists->stats.total_period; + u64 base_period = pair->stat.period; + + percent = 100.0 * base_period / total_period; + } + + return percent; +} + +static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) +{ + double percent = baseline_percent(he); + + return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); +} + +static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) +{ + double percent = baseline_percent(he); + const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; + + return scnprintf(hpp->buf, hpp->size, fmt, percent); +} + static int hpp__header_samples(struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; @@ -175,7 +206,7 @@ static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) { const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; - return scnprintf(hpp->buf, hpp->size, fmt, he->nr_events); + return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); } static int hpp__header_period(struct perf_hpp *hpp) @@ -194,7 +225,7 @@ static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) { const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; - return scnprintf(hpp->buf, hpp->size, fmt, he->period); + return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); } static int hpp__header_delta(struct perf_hpp *hpp) @@ -211,20 +242,22 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) { - struct hists *pair_hists = hpp->ptr; + struct hist_entry *pair = he->pair; + struct hists *pair_hists = pair ? pair->hists : NULL; + struct hists *hists = he->hists; u64 old_total, new_total; double old_percent = 0, new_percent = 0; double diff; const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; char buf[32] = " "; - old_total = pair_hists->stats.total_period; - if (old_total > 0 && he->pair) - old_percent = 100.0 * he->pair->period / old_total; + old_total = pair_hists ? pair_hists->stats.total_period : 0; + if (old_total > 0 && pair) + old_percent = 100.0 * pair->stat.period / old_total; - new_total = hpp->total_period; + new_total = hists->stats.total_period; if (new_total > 0) - new_percent = 100.0 * he->period / new_total; + new_percent = 100.0 * he->stat.period / new_total; diff = new_percent - old_percent; if (fabs(diff) >= 0.01) @@ -244,13 +277,15 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) } static int hpp__entry_displ(struct perf_hpp *hpp, - struct hist_entry *he __maybe_unused) + struct hist_entry *he) { + struct hist_entry *pair = he->pair; + long displacement = pair ? pair->position - he->position : 0; const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; char buf[32] = " "; - if (hpp->displacement) - scnprintf(buf, sizeof(buf), "%+4ld", hpp->displacement); + if (displacement) + scnprintf(buf, sizeof(buf), "%+4ld", displacement); return scnprintf(hpp->buf, hpp->size, fmt, buf); } @@ -267,6 +302,7 @@ static int hpp__entry_displ(struct perf_hpp *hpp, .entry = hpp__entry_ ## _name struct perf_hpp_fmt perf_hpp__format[] = { + { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, @@ -281,7 +317,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { #undef HPP__COLOR_PRINT_FNS #undef HPP__PRINT_FNS -void perf_hpp__init(bool need_pair, bool show_displacement) +void perf_hpp__init(void) { if (symbol_conf.show_cpu_utilization) { perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; @@ -298,13 +334,12 @@ void perf_hpp__init(bool need_pair, bool show_displacement) if (symbol_conf.show_total_period) perf_hpp__format[PERF_HPP__PERIOD].cond = true; +} - if (need_pair) { - perf_hpp__format[PERF_HPP__DELTA].cond = true; - - if (show_displacement) - perf_hpp__format[PERF_HPP__DISPL].cond = true; - } +void perf_hpp__column_enable(unsigned col, bool enable) +{ + BUG_ON(col >= PERF_HPP__MAX_INDEX); + perf_hpp__format[col].cond = enable; } static inline void advance_hpp(struct perf_hpp *hpp, int inc) @@ -319,6 +354,7 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, const char *sep = symbol_conf.field_sep; char *start = hpp->buf; int i, ret; + bool first = true; if (symbol_conf.exclude_other && !he->parent) return 0; @@ -327,9 +363,10 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, if (!perf_hpp__format[i].cond) continue; - if (!sep || i > 0) { + if (!sep || !first) { ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); advance_hpp(hpp, ret); + first = false; } if (color && perf_hpp__format[i].color) diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index bd7d460f844c..ebb4cc107876 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -30,7 +30,7 @@ void setup_browser(bool fallback_to_pager) if (fallback_to_pager) setup_pager(); - perf_hpp__init(false, false); + perf_hpp__init(); break; } } diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 882461a42830..fbd4e32d0743 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -271,7 +271,7 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, { switch (callchain_param.mode) { case CHAIN_GRAPH_REL: - return callchain__fprintf_graph(fp, &he->sorted_chain, he->period, + return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, left_margin); break; case CHAIN_GRAPH_ABS: @@ -292,9 +292,10 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, static size_t hist_entry__callchain_fprintf(struct hist_entry *he, struct hists *hists, - u64 total_period, FILE *fp) + FILE *fp) { int left_margin = 0; + u64 total_period = hists->stats.total_period; if (sort__first_dimension == SORT_COMM) { struct sort_entry *se = list_first_entry(&hist_entry__sort_list, @@ -307,17 +308,13 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, } static int hist_entry__fprintf(struct hist_entry *he, size_t size, - struct hists *hists, struct hists *pair_hists, - long displacement, u64 total_period, FILE *fp) + struct hists *hists, FILE *fp) { char bf[512]; int ret; struct perf_hpp hpp = { .buf = bf, .size = size, - .total_period = total_period, - .displacement = displacement, - .ptr = pair_hists, }; bool color = !symbol_conf.field_sep; @@ -330,22 +327,17 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret = fprintf(fp, "%s\n", bf); if (symbol_conf.use_callchain) - ret += hist_entry__callchain_fprintf(he, hists, - total_period, fp); + ret += hist_entry__callchain_fprintf(he, hists, fp); return ret; } -size_t hists__fprintf(struct hists *hists, struct hists *pair, - bool show_displacement, bool show_header, int max_rows, +size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, FILE *fp) { struct sort_entry *se; struct rb_node *nd; size_t ret = 0; - u64 total_period; - unsigned long position = 1; - long displacement = 0; unsigned int width; const char *sep = symbol_conf.field_sep; const char *col_width = symbol_conf.col_width_list_str; @@ -354,8 +346,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, struct perf_hpp dummy_hpp = { .buf = bf, .size = sizeof(bf), - .ptr = pair, }; + bool first = true; init_rem_hits(); @@ -367,8 +359,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, if (!perf_hpp__format[idx].cond) continue; - if (idx) + if (!first) fprintf(fp, "%s", sep ?: " "); + else + first = false; perf_hpp__format[idx].header(&dummy_hpp); fprintf(fp, "%s", bf); @@ -403,6 +397,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, if (sep) goto print_entries; + first = true; + fprintf(fp, "# "); for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { unsigned int i; @@ -410,8 +406,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, if (!perf_hpp__format[idx].cond) continue; - if (idx) + if (!first) fprintf(fp, "%s", sep ?: " "); + else + first = false; width = perf_hpp__format[idx].width(&dummy_hpp); for (i = 0; i < width; i++) @@ -441,24 +439,13 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, goto out; print_entries: - total_period = hists->stats.total_period; - for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); if (h->filtered) continue; - if (show_displacement) { - if (h->pair != NULL) - displacement = ((long)h->pair->position - - (long)position); - else - displacement = 0; - ++position; - } - ret += hist_entry__fprintf(h, max_cols, hists, pair, displacement, - total_period, fp); + ret += hist_entry__fprintf(h, max_cols, hists, fp); if (max_rows && ++nr_rows >= max_rows) goto out; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 9b5b21e7b032..39242dcee8f2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -138,7 +138,10 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, bool print_lines, bool full_paths, int min_pcnt, int max_lines); -#ifdef NO_NEWT_SUPPORT +#ifdef NEWT_SUPPORT +int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, + void(*timer)(void *arg), void *arg, int delay_secs); +#else static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, struct map *map __maybe_unused, int evidx __maybe_unused, @@ -148,9 +151,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, { return 0; } -#else -int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - void(*timer)(void *arg), void *arg, int delay_secs); #endif extern const char *disassembler_style; diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index ab1769426541..2bd51370ad28 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -33,39 +33,41 @@ extern int pager_use_color; extern int use_browser; -#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) -static inline void setup_browser(bool fallback_to_pager) -{ - if (fallback_to_pager) - setup_pager(); -} -static inline void exit_browser(bool wait_for_ok __maybe_unused) {} -#else +#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) void setup_browser(bool fallback_to_pager); void exit_browser(bool wait_for_ok); -#ifdef NO_NEWT_SUPPORT +#ifdef NEWT_SUPPORT +int ui__init(void); +void ui__exit(bool wait_for_ok); +#else static inline int ui__init(void) { return -1; } static inline void ui__exit(bool wait_for_ok __maybe_unused) {} -#else -int ui__init(void); -void ui__exit(bool wait_for_ok); #endif -#ifdef NO_GTK2_SUPPORT +#ifdef GTK2_SUPPORT +int perf_gtk__init(void); +void perf_gtk__exit(bool wait_for_ok); +#else static inline int perf_gtk__init(void) { return -1; } static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} -#else -int perf_gtk__init(void); -void perf_gtk__exit(bool wait_for_ok); #endif -#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ + +#else /* NEWT_SUPPORT || GTK2_SUPPORT */ + +static inline void setup_browser(bool fallback_to_pager) +{ + if (fallback_to_pager) + setup_pager(); +} +static inline void exit_browser(bool wait_for_ok __maybe_unused) {} +#endif /* NEWT_SUPPORT || GTK2_SUPPORT */ char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); @@ -105,7 +107,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2 extern char *perf_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -#ifdef NO_STRLCPY +#ifndef HAVE_STRLCPY extern size_t strlcpy(char *dest, const char *src, size_t size); #endif diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 66eb3828ceb5..03f830b48148 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -49,7 +49,7 @@ int dump_printf(const char *fmt, ...) return ret; } -#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) +#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) int ui__warning(const char *format, ...) { va_list args; diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index bb2e7d1007ab..dec98750b484 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -15,7 +15,14 @@ void trace_event(union perf_event *event); struct ui_progress; struct perf_error_ops; -#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) +#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) + +#include "../ui/progress.h" +int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); +#include "../ui/util.h" + +#else + static inline void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused, const char *title __maybe_unused) {} @@ -34,13 +41,7 @@ perf_error__unregister(struct perf_error_ops *eops __maybe_unused) return 0; } -#else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ - -#include "../ui/progress.h" -int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); -#include "../ui/util.h" - -#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ +#endif /* NEWT_SUPPORT || GTK2_SUPPORT */ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); int ui__error_paranoid(void); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ae89686102f4..186b87730396 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -154,8 +154,8 @@ error: return -ENOMEM; } -int perf_evlist__add_attrs(struct perf_evlist *evlist, - struct perf_event_attr *attrs, size_t nr_attrs) +static int perf_evlist__add_attrs(struct perf_evlist *evlist, + struct perf_event_attr *attrs, size_t nr_attrs) { struct perf_evsel *evsel, *n; LIST_HEAD(head); @@ -189,60 +189,6 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, return perf_evlist__add_attrs(evlist, attrs, nr_attrs); } -static int trace_event__id(const char *evname) -{ - char *filename, *colon; - int err = -1, fd; - - if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) - return -1; - - colon = strrchr(filename, ':'); - if (colon != NULL) - *colon = '/'; - - fd = open(filename, O_RDONLY); - if (fd >= 0) { - char id[16]; - if (read(fd, id, sizeof(id)) > 0) - err = atoi(id); - close(fd); - } - - free(filename); - return err; -} - -int perf_evlist__add_tracepoints(struct perf_evlist *evlist, - const char *tracepoints[], - size_t nr_tracepoints) -{ - int err; - size_t i; - struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); - - if (attrs == NULL) - return -1; - - for (i = 0; i < nr_tracepoints; i++) { - err = trace_event__id(tracepoints[i]); - - if (err < 0) - goto out_free_attrs; - - attrs[i].type = PERF_TYPE_TRACEPOINT; - attrs[i].config = err; - attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | - PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD); - attrs[i].sample_period = 1; - } - - err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); -out_free_attrs: - free(attrs); - return err; -} - struct perf_evsel * perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) { @@ -257,32 +203,18 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) return NULL; } -int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, - const struct perf_evsel_str_handler *assocs, - size_t nr_assocs) +int perf_evlist__add_newtp(struct perf_evlist *evlist, + const char *sys, const char *name, void *handler) { struct perf_evsel *evsel; - int err; - size_t i; - - for (i = 0; i < nr_assocs; i++) { - err = trace_event__id(assocs[i].name); - if (err < 0) - goto out; - - evsel = perf_evlist__find_tracepoint_by_id(evlist, err); - if (evsel == NULL) - continue; - err = -EEXIST; - if (evsel->handler.func != NULL) - goto out; - evsel->handler.func = assocs[i].handler; - } + evsel = perf_evsel__newtp(sys, name, evlist->nr_entries); + if (evsel == NULL) + return -1; - err = 0; -out: - return err; + evsel->handler.func = handler; + perf_evlist__add(evlist, evsel); + return 0; } void perf_evlist__disable(struct perf_evlist *evlist) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 3f1fb66be022..56003f779e60 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -51,26 +51,14 @@ void perf_evlist__delete(struct perf_evlist *evlist); void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); int perf_evlist__add_default(struct perf_evlist *evlist); -int perf_evlist__add_attrs(struct perf_evlist *evlist, - struct perf_event_attr *attrs, size_t nr_attrs); int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); -int perf_evlist__add_tracepoints(struct perf_evlist *evlist, - const char *tracepoints[], size_t nr_tracepoints); -int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, - const struct perf_evsel_str_handler *assocs, - size_t nr_assocs); - -#define perf_evlist__add_attrs_array(evlist, array) \ - perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) + #define perf_evlist__add_default_attrs(evlist, array) \ __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) -#define perf_evlist__add_tracepoints_array(evlist, array) \ - perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) - -#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ - perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) +int perf_evlist__add_newtp(struct perf_evlist *evlist, + const char *sys, const char *name, void *handler); int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh index 389590c1ad21..3ac38031d534 100755 --- a/tools/perf/util/generate-cmdlist.sh +++ b/tools/perf/util/generate-cmdlist.sh @@ -22,7 +22,7 @@ do }' "Documentation/perf-$cmd.txt" done -echo "#ifndef NO_LIBELF_SUPPORT" +echo "#ifdef LIBELF_SUPPORT" sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | sort | while read cmd @@ -35,5 +35,5 @@ do p }' "Documentation/perf-$cmd.txt" done -echo "#endif /* NO_LIBELF_SUPPORT */" +echo "#endif /* LIBELF_SUPPORT */" echo "};" diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 236bc9d98ff2..277947a669b2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -135,31 +135,47 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he, { switch (cpumode) { case PERF_RECORD_MISC_KERNEL: - he->period_sys += period; + he->stat.period_sys += period; break; case PERF_RECORD_MISC_USER: - he->period_us += period; + he->stat.period_us += period; break; case PERF_RECORD_MISC_GUEST_KERNEL: - he->period_guest_sys += period; + he->stat.period_guest_sys += period; break; case PERF_RECORD_MISC_GUEST_USER: - he->period_guest_us += period; + he->stat.period_guest_us += period; break; default: break; } } +static void he_stat__add_period(struct he_stat *he_stat, u64 period) +{ + he_stat->period += period; + he_stat->nr_events += 1; +} + +static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) +{ + dest->period += src->period; + dest->period_sys += src->period_sys; + dest->period_us += src->period_us; + dest->period_guest_sys += src->period_guest_sys; + dest->period_guest_us += src->period_guest_us; + dest->nr_events += src->nr_events; +} + static void hist_entry__decay(struct hist_entry *he) { - he->period = (he->period * 7) / 8; - he->nr_events = (he->nr_events * 7) / 8; + he->stat.period = (he->stat.period * 7) / 8; + he->stat.nr_events = (he->stat.nr_events * 7) / 8; } static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) { - u64 prev_period = he->period; + u64 prev_period = he->stat.period; if (prev_period == 0) return true; @@ -167,9 +183,9 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) hist_entry__decay(he); if (!he->filtered) - hists->stats.total_period -= prev_period - he->period; + hists->stats.total_period -= prev_period - he->stat.period; - return he->period == 0; + return he->stat.period == 0; } static void __hists__decay_entries(struct hists *hists, bool zap_user, @@ -223,7 +239,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) if (he != NULL) { *he = *template; - he->nr_events = 1; + if (he->ms.map) he->ms.map->referenced = true; if (symbol_conf.use_callchain) @@ -238,7 +254,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) if (!h->filtered) { hists__calc_col_len(hists, h); ++hists->nr_entries; - hists->stats.total_period += h->period; + hists->stats.total_period += h->stat.period; } } @@ -270,8 +286,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, cmp = hist_entry__cmp(entry, he); if (!cmp) { - he->period += period; - ++he->nr_events; + he_stat__add_period(&he->stat, period); /* If the map of an existing hist_entry has * become out-of-date due to an exec() or @@ -321,10 +336,14 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, .cpu = al->cpu, .ip = bi->to.addr, .level = al->level, - .period = period, + .stat = { + .period = period, + .nr_events = 1, + }, .parent = sym_parent, .filtered = symbol__parent_filter(sym_parent), .branch_info = bi, + .hists = self, }; return add_hist_entry(self, &entry, al, period); @@ -343,9 +362,13 @@ struct hist_entry *__hists__add_entry(struct hists *self, .cpu = al->cpu, .ip = al->addr, .level = al->level, - .period = period, + .stat = { + .period = period, + .nr_events = 1, + }, .parent = sym_parent, .filtered = symbol__parent_filter(sym_parent), + .hists = self, }; return add_hist_entry(self, &entry, al, period); @@ -410,12 +433,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, cmp = hist_entry__collapse(iter, he); if (!cmp) { - iter->period += he->period; - iter->period_sys += he->period_sys; - iter->period_us += he->period_us; - iter->period_guest_sys += he->period_guest_sys; - iter->period_guest_us += he->period_guest_us; - iter->nr_events += he->nr_events; + he_stat__add_stat(&iter->stat, &he->stat); if (symbol_conf.use_callchain) { callchain_cursor_reset(&callchain_cursor); @@ -518,7 +536,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, parent = *p; iter = rb_entry(parent, struct hist_entry, rb_node); - if (he->period > iter->period) + if (he->stat.period > iter->stat.period) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -579,8 +597,8 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h if (h->ms.unfolded) hists->nr_entries += h->nr_rows; h->row_offset = 0; - hists->stats.total_period += h->period; - hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; + hists->stats.total_period += h->stat.period; + hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events; hists__calc_col_len(hists, h); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f011ad4756e8..66cb31fe81d2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -98,9 +98,8 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows); void hists__inc_nr_events(struct hists *self, u32 type); size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); -size_t hists__fprintf(struct hists *self, struct hists *pair, - bool show_displacement, bool show_header, - int max_rows, int max_cols, FILE *fp); +size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, + int max_cols, FILE *fp); int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); int hist_entry__annotate(struct hist_entry *self, size_t privsize); @@ -118,9 +117,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); struct perf_hpp { char *buf; size_t size; - u64 total_period; const char *sep; - long displacement; void *ptr; }; @@ -135,6 +132,7 @@ struct perf_hpp_fmt { extern struct perf_hpp_fmt perf_hpp__format[]; enum { + PERF_HPP__BASELINE, PERF_HPP__OVERHEAD, PERF_HPP__OVERHEAD_SYS, PERF_HPP__OVERHEAD_US, @@ -148,13 +146,22 @@ enum { PERF_HPP__MAX_INDEX }; -void perf_hpp__init(bool need_pair, bool show_displacement); +void perf_hpp__init(void); +void perf_hpp__column_enable(unsigned col, bool enable); int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, bool color); struct perf_evlist; -#ifdef NO_NEWT_SUPPORT +#ifdef NEWT_SUPPORT +#include "../ui/keysyms.h" +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, + void(*timer)(void *arg), void *arg, int delay_secs); + +int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, + void(*timer)(void *arg), void *arg, + int refresh); +#else static inline int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, const char *help __maybe_unused, @@ -177,17 +184,13 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self } #define K_LEFT -1 #define K_RIGHT -2 -#else -#include "../ui/keysyms.h" -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, - void(*timer)(void *arg), void *arg, int delay_secs); +#endif -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, +#ifdef GTK2_SUPPORT +int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, void(*timer)(void *arg), void *arg, int refresh); -#endif - -#ifdef NO_GTK2_SUPPORT +#else static inline int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, const char *help __maybe_unused, @@ -197,11 +200,6 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, { return 0; } - -#else -int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, - void(*timer)(void *arg), void *arg, - int refresh); #endif unsigned int hists__sort_list_width(struct hists *self); diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h index 9bcdc844b330..2a030c5af3aa 100644 --- a/tools/perf/util/include/linux/rbtree.h +++ b/tools/perf/util/include/linux/rbtree.h @@ -1,3 +1,2 @@ #include <stdbool.h> -#include <stdbool.h> #include "../../../../include/linux/rbtree.h" diff --git a/tools/perf/util/include/linux/rbtree_augmented.h b/tools/perf/util/include/linux/rbtree_augmented.h new file mode 100644 index 000000000000..9d6fcdf1788b --- /dev/null +++ b/tools/perf/util/include/linux/rbtree_augmented.h @@ -0,0 +1,2 @@ +#include <stdbool.h> +#include "../../../../include/linux/rbtree_augmented.h" diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ead5316b3f89..6109fa4d14cd 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -162,7 +162,7 @@ int map__load(struct map *self, symbol_filter_t filter) pr_warning(", continuing without symbols\n"); return -1; } else if (nr == 0) { -#ifndef NO_LIBELF_SUPPORT +#ifdef LIBELF_SUPPORT const size_t len = strlen(name); const size_t real_len = len - sizeof(DSO__DELETED); diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 443fc116512b..2bc9e70df7e2 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -384,6 +384,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, return usage_with_options_internal(usagestr, options, 1); if (internal_help && !strcmp(arg + 2, "help")) return parse_options_usage(usagestr, options); + if (!strcmp(arg + 2, "list-opts")) + return PARSE_OPT_LIST; switch (parse_long_opt(ctx, arg + 2, options)) { case -1: return parse_options_usage(usagestr, options); @@ -422,6 +424,12 @@ int parse_options(int argc, const char **argv, const struct option *options, exit(129); case PARSE_OPT_DONE: break; + case PARSE_OPT_LIST: + while (options->type != OPTION_END) { + printf("--%s ", options->long_name); + options++; + } + exit(130); default: /* PARSE_OPT_UNKNOWN */ if (ctx.argv[0][1] == '-') { error("unknown option `%s'", ctx.argv[0] + 2); diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index abc31a1dac1a..7bb5999940ca 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h @@ -140,6 +140,7 @@ extern NORETURN void usage_with_options(const char * const *usagestr, enum { PARSE_OPT_HELP = -1, PARSE_OPT_DONE, + PARSE_OPT_LIST, PARSE_OPT_UNKNOWN, }; diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index bd7497711424..a8c49548ca48 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -22,7 +22,7 @@ static const char *get_perf_dir(void) return "."; } -#ifdef NO_STRLCPY +#ifndef HAVE_STRLCPY size_t strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 316dbe7f86ed..5a4f2b6f3738 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -1,7 +1,7 @@ #ifndef __PERF_REGS_H #define __PERF_REGS_H -#ifndef NO_PERF_REGS +#ifdef HAVE_PERF_REGS #include <perf_regs.h> #else #define PERF_REGS_MASK 0 @@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused) { return NULL; } -#endif /* NO_PERF_REGS */ +#endif /* HAVE_PERF_REGS */ #endif /* __PERF_REGS_H */ diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 12d634792de5..5786f323b597 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -43,6 +43,15 @@ extern struct sort_entry sort_sym_from; extern struct sort_entry sort_sym_to; extern enum sort_type sort__first_dimension; +struct he_stat { + u64 period; + u64 period_sys; + u64 period_us; + u64 period_guest_sys; + u64 period_guest_us; + u32 nr_events; +}; + /** * struct hist_entry - histogram entry * @@ -52,16 +61,11 @@ extern enum sort_type sort__first_dimension; struct hist_entry { struct rb_node rb_node_in; struct rb_node rb_node; - u64 period; - u64 period_sys; - u64 period_us; - u64 period_guest_sys; - u64 period_guest_us; + struct he_stat stat; struct map_symbol ms; struct thread *thread; u64 ip; s32 cpu; - u32 nr_events; /* XXX These two should move to some tree widget lib */ u16 row_offset; @@ -73,12 +77,13 @@ struct hist_entry { u8 filtered; char *srcline; struct symbol *parent; + unsigned long position; union { - unsigned long position; struct hist_entry *pair; struct rb_root sorted_chain; }; struct branch_info *branch_info; + struct hists *hists; struct callchain_root callchain[0]; }; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b441b07172b7..8b6ef7fac745 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -12,7 +12,7 @@ #include <byteswap.h> #include <libgen.h> -#ifndef NO_LIBELF_SUPPORT +#ifdef LIBELF_SUPPORT #include <libelf.h> #include <gelf.h> #include <elf.h> @@ -46,10 +46,10 @@ char *strxfrchar(char *s, char from, char to); * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; * for newer versions we can use mmap to reduce memory usage: */ -#ifdef LIBELF_NO_MMAP -# define PERF_ELF_C_READ_MMAP ELF_C_READ -#else +#ifdef LIBELF_MMAP # define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP +#else +# define PERF_ELF_C_READ_MMAP ELF_C_READ #endif #ifndef DMGL_PARAMS @@ -233,7 +233,7 @@ struct symsrc { int fd; enum dso_binary_type type; -#ifndef NO_LIBELF_SUPPORT +#ifdef LIBELF_SUPPORT Elf *elf; GElf_Ehdr ehdr; diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index a78c8b303bb5..cb6bc503a792 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -13,7 +13,7 @@ struct unwind_entry { typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); -#ifndef NO_LIBUNWIND_SUPPORT +#ifdef LIBUNWIND_SUPPORT int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct machine *machine, struct thread *thread, @@ -31,5 +31,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, { return 0; } -#endif /* NO_LIBUNWIND_SUPPORT */ +#endif /* LIBUNWIND_SUPPORT */ #endif /* __UNWIND_H */ diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 2055cf38041c..99664598bc1a 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,7 +1,7 @@ #include "../perf.h" #include "util.h" #include <sys/mman.h> -#ifndef NO_BACKTRACE +#ifdef BACKTRACE_SUPPORT #include <execinfo.h> #endif #include <stdio.h> @@ -165,7 +165,7 @@ size_t hex_width(u64 v) } /* Obtain a backtrace and print it to stdout. */ -#ifndef NO_BACKTRACE +#ifdef BACKTRACE_SUPPORT void dump_stack(void) { void *array[16]; diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index c05bcd293d8c..b51d787176d3 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1873,10 +1873,10 @@ sub make_oldconfig { apply_min_config; } - if (!run_command "$make oldnoconfig") { - # Perhaps oldnoconfig doesn't exist in this version of the kernel + if (!run_command "$make olddefconfig") { + # Perhaps olddefconfig doesn't exist in this version of the kernel # try a yes '' | oldconfig - doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; + doprint "olddefconfig failed, trying yes '' | make oldconfig\n"; run_command "yes '' | $make oldconfig" or dodie "failed make config oldconfig"; } @@ -1929,7 +1929,7 @@ sub build { # old config can ask questions if ($type eq "oldconfig") { - $type = "oldnoconfig"; + $type = "olddefconfig"; # allow for empty configs run_command "touch $output_config"; @@ -1959,7 +1959,7 @@ sub build { load_force_config($minconfig); } - if ($type ne "oldnoconfig") { + if ($type ne "olddefconfig") { run_command "$make $type" or dodie "failed make config"; } @@ -2458,8 +2458,7 @@ my %config_set; # config_off holds the set of configs that the bad config had disabled. # We need to record them and set them in the .config when running -# oldnoconfig, because oldnoconfig does not turn off new symbols, but -# instead just keeps the defaults. +# olddefconfig, because olddefconfig keeps the defaults. my %config_off; # config_off_tmp holds a set of configs to turn off for now @@ -3250,7 +3249,7 @@ sub test_this_config { } # Remove this config from the list of configs - # do a make oldnoconfig and then read the resulting + # do a make olddefconfig and then read the resulting # .config to make sure it is missing the config that # we had before my %configs = %min_configs; |